【问题标题】:Why doesn't Python use C++/Java-like syntax to define instance variables?为什么 Python 不使用类似 C++/Java 的语法来定义实例变量?
【发布时间】:2012-11-03 07:48:17
【问题描述】:

这困扰了我几个小时,因为我来自 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 语言的工作相反(他们为大写引入了 static 关键字,这让你明确地说你想要一个静态变量)?对于 Python 的新手来说,这是一个惊喜。

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

class x(object):
    mem = []

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

我必须运行它才能确定要打印的内容。我什至无法猜测!

【问题讨论】:

  • 其他语言工作方式的直觉是什么?不同的语言做事不同,看起来你只是习惯了另一种方式。
  • 看起来不对,因为你带了行李。这实际上是合乎逻辑的:在class ...: 之后,字段是类变量。只有在实例初始化器中声明实例变量才有意义。当然,这不是 C++/Java 的思维方式,但完全可以理解。
  • 没有“默认行为”。只有一种替代方案有点类似于其他语言中可用的语法(可能不是故意的)。对我来说,这个句法特征的行为很有意义:类属性是绑定在类级别的属性,定义一个属性是通过在类定义级别进行分配来完成的——在与方法相同的级别,这也住在班里。这也完全符合没有声明的事实,并且所有看起来像声明的东西,在每个层面上都是一个声明。
  • 我在 Java 中遇到了同样的问题 ;) 但我是这么想的:如果你没有像 static、private、public 这样的可见性修饰符,你怎么能区分变量的范围?您明确声明:self. = ...范围/命名空间 self 中的变量 获取值 。面向对象只是一个概念,取决于语言设计者如何解释/实现它。

标签: java python class instance-variables


【解决方案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
...

【讨论】:

  • 这不是唯一的好用处。类属性有用途,就像静态 OOP 语言中的静态变量有用途一样。 (尽管用途不同:静态变量通常应该是模块级的,就像静态方法通常应该是模块级的函数一样。)
【解决方案2】:

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

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

那么你只需要了解 Python 的属性查找模型。它的工作原理几乎与大多数 shell 中的PATH 分辨率相同。例如,在 bash 中,当您执行命令 (ls) 时,将搜索路径中的第一个条目,然后搜索第二个条目,依此类推,找到的第一个版本的命令就是执行的那个。但是在这种情况下,路径看起来像这样(至少在单继承的简单情况下):

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

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

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

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

【讨论】:

  • 这与我想写的答案几乎相同,但没有时间。干得好。
猜你喜欢
  • 2013-11-02
  • 2014-08-20
  • 2012-06-23
  • 2012-05-20
  • 2018-02-08
  • 1970-01-01
  • 2012-08-25
  • 2017-09-06
相关资源
最近更新 更多