7

这是我制作的一个非常简单的代码,用于演示我遇到的问题。这里发生的是,我正在创建同一个类的两个不同实例,但是更改一个实例的属性将更改另一个实例的相应属性。我不确定这是为什么。这在 Python 中是正常的还是我遇到了完全搞砸的东西?

class exampleClass(object):

    attribute1=0
    attribute2="string"

x=exampleClass
x.attribute1=20
x.attribute2="Foo"

y=exampleClass
y.attribute1=60
y.attribute2="Bar"

print("X attributes: \n")
print(x.attribute1)
print(x.attribute2)

print("Y attributes: \n")
print(y.attribute1)
print(y.attribute2)

这是程序从我的控制台中出来的样子:

>>> 
X attributes: 

60
Bar
Y attributes: 

60
Bar
>>> 

我觉得应该说:

X attributes:

20
Foo
Y attributes:

60
Bar

我究竟做错了什么?

4

4 回答 4

9

当您需要实例属性时,您正在创建类属性。用这个:

class exampleClass(object):
    def __init__(self):
        self.attribute1 = 0
        self.attribute2 = "string"

此外,您没有创建任何 exampleClass 实例,您需要这个:

x = exampleClass()
y = exampleClass()

您的代码只是为类使用新名称,并更改其属性。

于 2012-06-26T23:41:52.113 回答
5

您已将属性设置为类属性。这意味着它们的作用域是类本身,而不是类的对象。

如果您想要对象范围,您可以执行以下操作:

class exampleClass(object):
        def __init__(self):
            self.attribute1=0
            self.attribute2="string"

x = exampleClass()
y = exampleClass()

然后,当您更改对象的属性值时,它只会影响该特定对象,而不是该类的所有对象。

于 2012-06-26T23:43:25.580 回答
3

进行了修改,使其更清晰。

使用您拥有的代码,您的问题是您正在使变量 x 和 y 引用类定义,而不是实例化我认为现在已经作为所有讨论和帖子的问题浮出水面的对象。

x = exampleClass

现在意味着 x 现在指向类定义。这很有趣,因为您将 attribute1 作为 exampleClass 的变量,您可以这样做:

x.attribute1 = 3

现在,如果您执行以下操作:

exampleClass.attribute1

您现在将看到 3,而不是您最初设置的 0!

要实例化类的对象,您需要执行以下操作:

x = exampleClass()
y = exampleClass()

现在两个变量都引用了新对象,每个对象都有自己的属性,所以如果你这样做了:

x.attribute1 = 219

然后你会发现 y.attribute1 没有被修改 :) 使用类和函数的名称在 python 中很常见作为对定义的引用。所以要小心,如果你想实例化一个对象,请确保使用括号,如果你想调用一个函数,请确保你也这样做,否则使用名称是对定义的引用。

我建议您阅读 Ned Batchelder 的答案(以及现在的其他答案),因为您应该使用init函数以这种方式制作实例变量,因为它更干净,更符合大多数人遵循的设计标准。

但总的来说,由于它继承自 Object 类,因此您可以假设这样做会创建实例(带括号)等,因此您可以修改对象值,因为我相信即使没有“self”,它们也应该是实例变量。

于 2012-06-26T23:42:56.637 回答
2

在 Python 中,类也是对象。因此,它们可以分配给变量并具有自己的属性,与任何其他对象相同。

您在块中绑定的所有名称都将class成为所创建类的属性。它们不是该类未来实例的属性。但是当你尝试从一个实例中读取一个属性并且该实例没有该属性时,Python 默认会查看该实例的类的属性,如果找到了就会返回该属性。这实际上就是 Python 中方法的工作方式。它们只是类的属性,当您尝试从实例中检索它们(它们不存在的地方)时,它们会通过查看类来找到。

考虑到这一点,您的程序不会像您认为的那样做。

class exampleClass(object):

    attribute1=0
    attribute2="string"

在这里,您创建了一个名为 的类exampleClass,具有两个属性attribute1attribute2。它们不是实例属性;这是人们学习 Python 的一个非常常见的错误。您需要训练自己摆脱这种情况,因为对于简单的示例,它通常看起来“好像”它们是实例属性。在块中绑定名称class会在类对象上创建属性。创建实例属性的唯一方法是在实例存在时获取对实例的引用并为其分配属性;Python 为您提供了__init__方法(将在创建实例时调用)作为执行此操作的地方。

所以基本的经验法则是:类块中定义的名称是类对象的属性,分配为selfin__init__属性的名称是该类所有实例的属性。

另一个问题进一步加剧了您的困惑:

x=exampleClass
x.attribute1=20
x.attribute2="Foo"

因为类和 Python 中的所有其他东西一样是对象,所以这是完全合理的 Python 代码,但它并没有按照你的想法去做。您实际上还没有创建类的实例;为此,您需要像在exampleClass(). 裸名exampleClass只是指类对象本身,因此您只需将名称绑定x到该对象,然后为其分配一些属性。自然,当您随后也绑定y到类对象并通过 为该对象分配属性时,y引用的对象x受到影响(它是同一个对象)。

于 2012-06-27T00:24:32.823 回答