2

很抱歉发布这样奇怪的问题,通常当我感到困惑时,我只是“跟着它走”,直到我顿悟,然后把它整理出来,但def __init__(self):在我的课堂上打电话似乎完全是多余的,而且似乎把它排除在外也同样有效:

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__,而且这里的其他线程并不像我希望的那样清楚。我能做些什么来让这个“点击”吗?

4

5 回答 5

6

将赋值语句放在类定义中不会声明实例属性;它设置类属性。如果您这样做,所有宠物将共享相同nametype_of_pet、 和number_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

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

于 2013-08-19T22:32:08.503 回答
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_pet放入fred实例中。因此,通常使用类级定义作为实例的默认值。

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

class Pet:
    vaccinations = []

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

因为fido.vaccinations最终成为对在类级别定义的单个列表的引用。相反,您会使用__init__给每只宠物自己的独立列表。

就个人而言,我越来越相信使用类级别属性作为非可变类型的默认值会造成更多的混乱,而不是它的价值,并且应该只为真正应该在类级别而不是每个实例跟踪的东西保存。但这是意见。

于 2013-08-19T22:35:49.447 回答
1

__init__是一种构造函数,当创建类的实例时,python__init__()在实例化期间调用以定义在实例化类时应该发生的附加行为,基本上是为该对象设置一些起始值或运行实例化所需的例程。

来源)

例如,您可以将您的 Pet 类更改为:

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

并使用以下命令创建一个新实例:

alice = Pet("Pterodactyl")

如果您在__init__函数之外初始化类变量,则每个实例都将共享该值。这对静态类很有用,但我认为您不希望在“普通”类上出现这种行为。

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

于 2013-08-19T22:33:11.620 回答
1

您在问为什么__init__()在实例化后可以在类上分配属性时需要它。

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

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

于 2013-08-19T22:38:34.007 回答
0

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

于 2013-08-19T22:32:14.427 回答