2013-08-19 106 views
2

抱歉发布这样一个奇怪的问题,通常当我感到困惑时,我只是“随它而行”,直到我有了顿悟,然后将其整理出来,但在我的课程中调用def __init__(self):似乎完全是多余的,似乎只是让它工作而已还有:使用类创建对象,为什么我需要__init __(self,args):?

class Pet(object): 
    type_of_pet = "" 
    number_of_legs = 0 
    name = "" 

让我创建:

fred = pet() 
fred.type_of_pet = "alligator" 

还是一样,好像我是在类更改为:

class Pet(object): 
    def __init__(self): 
     type_of_pet = "" 

alice = Pet() 
alice.type_of_pet = "Pterodactyl" 

我只是没有得到为什么我需要__init__和其他线程在这里没有我希望的那么清晰。有什么我可以做这个“点击”?

+0

您_definitely_不想在'__init__'中写入'type_of_pet =“”'。这只是设置一个立即消失的局部变量。你可能想要'self.type_of_pet =“”'。但更好的是,您可能希望将'type_of_pet'作为参数,并将该值复制到该属性。 – abarnert

+0

另外,真的没有理由在这个类上拥有这三个类的属性。这不是Java或C++,您需要先声明变量和成员,然后才能使用它们。事实上,你正在做的是在类上创建成员,由所有实例共享,然后通过在具有相同名称的实例上创建成员来隐藏它们。 – abarnert

回答

6

将赋值语句放在类定义中不会声明实例属性;它设置了类的属性。如果你这样做,所有的宠物将共享相同的name,type_of_petnumber_of_legs

__init__是,除其他事项外,用于设置实例的属性:

def __init__(self, type_of_pet, name, number_of_legs): 
    self.type_of_pet = type_of_pet 
    self.name = name 
    self.number_of_legs = number_of_legs 

这将在实例上设置属性,而不是类,所以每个对象将有自己的名称,类型和腿计数。

+0

好吧,我注意到把东西放在类下面就像是一个全局变量......初始化只是让我每次做newThing = Class()我都指派“本地”属性而不是“全局变量”? – ford

+0

@福尔德:全局/本地和类/实例是非常相似的概念,并且将一些东西放在'__init__'和类级别之间非常类似于使其成为本地而不是全局。请注意,属性绑定到对象而不是'__init__'方法,因此对对象的任何方法调用都将看到相同的属性,而不是创建新的属性。这与函数中的局部变量不同。 – user2357112

+0

太棒了。这真的很有帮助。非常感谢。 – ford

0

当您直接在类中定义成员时,这些成员将成为类本身的一部分,而不是类的实例的一部分。您仍然可以通过实例访问它们,但每个实例都没有自己的实例。

1

__init__ is a kind of constructor, when a instance of a class is created, python calls __init__() during the instantiation to define additional behavior that should occur when a class is instantiated, basically setting up some beginning values for that object or running a routine required on instantiation.

source)

例如,你可以改变你的宠物类:

class Pet(object): 
    def __init__(self, type_of_pet): 
     self.type_of_pet = type_of_pet 

,并作出新的实例有:

alice = Pet("Pterodactyl") 

如果初始化类变量在__init__函数之外,每个实例将共享th在价值。这对静态类很有用,但我不认为你想在“普通”类上使用这种行为。

顺便说一句,你不能使用type_of_pet=""__init__,它必须是self.type_of_pet=""

2

__init__在创建类后立即在您的类的每个实例上调用。这是进行实例级初始化的正确位置。

您的type_of_pet和您的第一个示例中定义的其他属性是类级别的信息。该表格声明Pet类本身具有type_of_pet值,并且该值存在于与您可能定义的任何方法相同的级别。

当你为一个名字检查一个实例时,它将得到分配给该实例的值(如果有的话),或者如果没有的话,则转到类的级别。所以这个:

fred = Pet() 
print fred.type_of_pet 

实际检查类本身type_of_pet

分配将只修改对象,你实际调用它,所以这在实例级别设置一个值:

fred.type_of_pet = 'alligator' 

这使得不改变类,只是把一个值的名称type_of_petfred实例。因此,使用类级定义作为实例的默认值很常见。

但是,这会给你带来麻烦的是像列表这样的可变类型。这不会做你所期望的:

class Pet: 
    vaccinations = [] 

fido = Pet() 
fido.vaccinations.append('rabies') 

因为fido.vaccinations结束是在类级别定义的单一列表的引用。相反,你会使用__init__给每个宠物自己的独立名单。个人而言,我越来越认为使用类级属性作为默认类型的不变性类型会造成更多的混乱而不是它的价值,应该只保存用于真正应该在类级而不是每级跟踪的事物实例。但那是意见。

1

你问为什么你需要__init__()当你可以在类实例化后分配属性。

答案是,所以你可以在实例化对象时传递属性值,就像你应该的那样。这不仅可以节省你打字的时间,实例化后,在类上分配属性容易出错:如果不小心将其分配为number_off_legs而不是number_of_legs?这本身并不是一个错误,因为属性可以被命名为任何东西,但是会导致其他代码(预计number_of_legs)失败,或者在您的情况下会导致错误的数据(因为此类上的默认值将用于此处点)。此外,如果您需要更改属性名称,则该名称为全部为您的代码,因此您需要在很多地方更改它。

因此,为了避免这些问题,您需要编写一个小函数来创建对象,然后在其上分配属性,并在给出对象之前执行任何其他必要的初始化(打开文件,创建从属对象等)反对你。这是您的__init__()方法,Python有助于将它附加到您的类,以便您可以实例化对象并一次传入所有属性值。当你只是存储一些数据时,它看起来并不是很有用,但是当你的类变得更复杂时,你会发现它非常方便。

相关问题