Python 和对象/类属性 - 发生了什么?

发布于 2024-09-05 08:20:25 字数 405 浏览 8 评论 0原文

有人可以解释为什么Python会执行以下操作吗?

>>> class Foo(object):
...   bar = []
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]
>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]
>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]

真是比较混乱啊!

Can someone explain why Python does the following?

>>> class Foo(object):
...   bar = []
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]
>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]
>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]

It's rather confusing!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

把昨日还给我 2024-09-12 08:20:25

这是因为按照您的编写方式,bar 是一个类变量而不是实例变量。

要定义实例变量,请将其绑定在构造函数中:

class Foo(object):
  def __init__(self):
    self.bar = []

请注意,它现在属于 Foo (self) 的单个实例,而不是 Foo 类,当你分配给它时,你会看到你期望的结果。

This is because the way you have written it, bar is a class variable rather than an instance variable.

To define an instance variable, bind it in the constructor:

class Foo(object):
  def __init__(self):
    self.bar = []

Note that it now belongs to a single instance of Foo (self) rather than the Foo class, and you will see the results you expect when you assign to it.

妖妓 2024-09-12 08:20:25

正如其他人所说,编写的代码创建了一个类变量而不是一个实例变量。您需要在 __init__ 中进行赋值来创建实例变量。

希望这个带注释的代码副本有助于解释每个阶段发生的情况:

>>> class Foo(object):
...   bar = []          # defines a class variable on Foo (shared by all instances)
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)     # appends the value 1 to the previously empty list Foo.bar
>>> b.bar               # returns the value of the class variable Foo.bar
[1]
>>> a.bar = 1           # binds 1 to the instance variable a.bar, masking the access
>>> a.bar               # you previously had to the class variable through a.bar
1
>>> b.bar               # b doesn't have an instance variable 'bar' so this still
[1]                     # returns the class variable
>>> a.bar = []          # bind a's instance variable to to an empty list
>>> a.bar
[]
>>> b.bar               # b doesn't have an instance variable 'bar' so this still
[1]                     # returns the class variable
>>> del a.bar           # unbinds a's instance variable unmasking the class variable
>>> a.bar               # so a.bar now returns the list with 1 in it.
[1]

此外,在之后打印出 Foo.bar 的值(通过类而不是通过实例访问的类变量)你的每一个陈述都可能有助于澄清正在发生的事情。

As others have said the code as written creates a class variable rather than an instance variable. You need to assign in __init__ to create an instance variable.

Hopefully this annotated copy of your code is helpful in explaining what's going on at each stage:

>>> class Foo(object):
...   bar = []          # defines a class variable on Foo (shared by all instances)
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)     # appends the value 1 to the previously empty list Foo.bar
>>> b.bar               # returns the value of the class variable Foo.bar
[1]
>>> a.bar = 1           # binds 1 to the instance variable a.bar, masking the access
>>> a.bar               # you previously had to the class variable through a.bar
1
>>> b.bar               # b doesn't have an instance variable 'bar' so this still
[1]                     # returns the class variable
>>> a.bar = []          # bind a's instance variable to to an empty list
>>> a.bar
[]
>>> b.bar               # b doesn't have an instance variable 'bar' so this still
[1]                     # returns the class variable
>>> del a.bar           # unbinds a's instance variable unmasking the class variable
>>> a.bar               # so a.bar now returns the list with 1 in it.
[1]

Also, printing out the value of Foo.bar (the class variable accessed via the class rather than via an instance) after each of your statements might help clarify what is going on.

洒一地阳光 2024-09-12 08:20:25

当您在类中声明一个元素时,该元素将被该类的所有实例共享。要分别创建属于每个实例的正确类成员,请在 __init__ 中创建它,如下所示:

class Foo(object):
    def __init__(self):
        self.bar = []

When you declare an element in the class like that it is shared by all instances of the class. To make a proper class member that belongs to each instance, separately, create it in __init__ like the following:

class Foo(object):
    def __init__(self):
        self.bar = []
谎言月老 2024-09-12 08:20:25

一开始,bar是一个类变量,它在ab之间共享,两者都是a.bar和 b.bar 引用同一个对象。

当您向 a.bar 分配新值时,这不会覆盖类变量,而是向 a 对象添加一个新的实例变量,从而在您指定时隐藏该类变量。访问a.bar。如果删除 a.bar (实例变量),则 a.bar 再次解析为类变量。

另一方面,b.bar 始终引用类变量,它不受 a 对象上附加的 bar 或分配的任何值的影响对此。

要设置类变量,您可以通过类本身访问它:

Foo.bar = 1

In the beginning, bar is a class variable and it is shared between a and b, both a.bar and b.bar refer to the same object.

When you assign a new value to a.bar, this does not overwrite the class variable, it adds a new instance variable to the a object, hiding the class variable when you access a.bar. If you delete a.bar (the instance variable), then a.bar resolves again to the class variable.

b.bar on the other hand always refers to the class variable, it's not influenced by the additional bar on the a object or any values assigned to that.

To set the class variable you can access it through the class itself:

Foo.bar = 1
夜雨飘雪 2024-09-12 08:20:25
>>> class Foo(object):
...   bar = []
...

bar 是一个共享类变量,而不是实例变量。我相信这可以解决您的大部分困惑。要使其成为实例变量,请根据其他答案在类的 __init__ 中定义它。

>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]

这就是证明。

>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]

现在您已将 a.bar 重新定义为实例变量。这就是默认情况下在外部定义变量时发生的情况。

>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]

又一样。 b.bar 仍然是共享类变量。

>>> class Foo(object):
...   bar = []
...

bar is a shared class variable, not an instance variable. I believe that deals with most of your confusion. To make it a instance var, define it in class's __init__ per the other answers.

>>> a = Foo()
>>> b = Foo()
>>> a.bar.append(1)
>>> b.bar
[1]

This is the proof of that.

>>> a.bar = 1
>>> a.bar
1
>>> b.bar
[1]

Now you've redefined a.bar as a instance variable. That's what happens when you define variables externally by default.

>>> a.bar = []
>>> a.bar
[]
>>> b.bar
[1]
>>> del a.bar
>>> a.bar
[1]

Same again. b.bar is still the shared class variable.

与之呼应 2024-09-12 08:20:25

与此相关的是,您应该意识到您可能很快就会看到的这个陷阱:

class A:
   def __init__(self, mylist = []):
      self.mylist = mylist


a = A()
a2 = A()

a.mylist.append(3)
print b.mylist #prints [3] ???

这让很多人感到困惑,并且与代码的解释方式有关。 Python 实际上首先解释函数标题,因此它会计算 __init__(self, mylist = []) 并将对该列表的引用存储为默认参数。这意味着 A 的所有实例(除非提供它们自己的列表)都将引用原始列表。执行此类操作的正确代码是,

class A:
   def __init__(self, mylist=None):
      if mylist:
         self.mylist = mylist
      else:
         self.mylist = []

或者如果您想要更短的表达式,您可以使用三元语法:

self.mylist = mylist if mylist else []

On a related note, you should be aware of this pitfall that you might see sometime soon:

class A:
   def __init__(self, mylist = []):
      self.mylist = mylist


a = A()
a2 = A()

a.mylist.append(3)
print b.mylist #prints [3] ???

This confuses a lot of folks and has to do with how the code is interpreted. Python actually interprets the function headings first, so it evaluates __init__(self, mylist = []) and stores a reference to that list as the default parameter. That means that all instances of A will (unless provided their own list) reference the original list. The correct code for doing such a thing would be

class A:
   def __init__(self, mylist=None):
      if mylist:
         self.mylist = mylist
      else:
         self.mylist = []

or if you want a shorter expression you can use the ternary syntax:

self.mylist = mylist if mylist else []
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文