4

这困扰了我几个小时,因为我来自 C++ 世界。我终于发现了发生了什么,但我不知道为什么这是默认行为。我想了解为什么这种语言是这样设计的。

我想要一个实例变量mem。所以我尝试了这个:

class x(object):
   mem = []

obj = x()
obj.mem.append(1)
print(obj.mem)
objTWO = x()
objTWO.mem.append(2)
print(objTWO.mem)

打印这个:

[1] 

[1, 2]

然而:

class x(object):

    def __init__(self):
        self.mem = []

obj = x()
obj.mem.append(1)
print(obj.mem)
objTWO = x()
objTWO.mem.append(2)
print(objTWO.mem)

印刷

[1]

[2]

为什么第一个是默认行为?这里的直觉是什么,因为它与许多主流 OO 语言的工作方式相反(它们引入了statictop case 的关键字,这让你明确地说你想要一个静态变量)?对于 Python 的新手来说,这是一个惊喜。

此外,您似乎可以拥有同名的实例变量和类变量:

class x(object):
    mem = []

    def __init__(self):
        self.mem = []

我必须运行它来弄清楚要打印什么。我也猜不透!

4

2 回答 2

8

直觉是,在 Python 中,一切都是对象,包括类本身。Python 中没有“静态”关键字这样的东西。有类,它们是对象,这些类具有属性。类定义中出现的所有内容都是类属性——包括方法和其他类型的属性。

这种设计的好处是简单性和一致性。公共或私有,或静态和非静态属性之间没有区别。类和实例属性之间的区别自然地通过类构造函数出现。当__init__被调用时(间接通过ClassName(params)),它通过参数接收类的新实例,self然后直接修改该实例。一切都是通过已经定义的构造显式发生的——您无需了解任何新语法或新关键字即可查看创建实例时发生的情况。

那么你只需要了解 Python 的属性查找模型。PATH它的工作原理与大多数 shell中的分辨率几乎相同。例如,在 bash 中,当您执行命令ls(但是在这种情况下,路径看起来像这样(至少在单继承的简单情况下):

instance; class; superclass; superclass; ... and so on

这与 c 或 c++ 中嵌套作用域中的名称解析并没有太大区别。你抱怨:

更糟糕的是,您似乎可以拥有同名的实例变量和类变量。

但这真的比 c 允许您int i;在一个块中定义,创建一个内部块,然后定义另一个int i;掩盖原始块的事实更令人困惑吗?

于 2012-11-14T19:11:18.073 回答
-1

我同意这是违反直觉的,但它有一个很好的用途——别名功能。

这是我前段时间写的一个图书馆,为了长度而删减了

...
class UndrawnTurtle():
    """Acts just like the turtle package, but without bringing up a window to show it."""
...

    def forward(self, distance):
        angle_radians = math.radians(self.angle)

        self.x = self.x + math.cos(angle_radians) * distance
        self.y = self.y + math.sin(angle_radians) * distance

        self._visit()

...
    # Now for some aliases. Everything that's implemented in this class
    # should be aliased the same way as the actual api.
    fd = forward
...
于 2012-11-14T19:02:56.453 回答