Python中相同类型的类变量

sas*_*uke 11 python oop

在学习Python时,通过典型的Point类示例,我注意到由于某种原因,我不能拥有与类相同类型的类级别(静态变量).例如

class Point:

  ORIGIN = Point() # doesn't work

  def __init__(self, x=0, y=0):
    self.x = x
    self.y = y
Run Code Online (Sandbox Code Playgroud)

虽然在Java中也是如此:

class Point {

  public static void main(final String[] args) { }

  private static final Point ORIGIN = new Point(0, 0);

  private int x;

  private int y;

  public Point(int x, int y) {
    this.x = x;
    this.y = y;
  }

}
Run Code Online (Sandbox Code Playgroud)

问题是:有没有办法在Python中实现相同的目标.现在我依赖于模块级变量,我不喜欢那个解决方案.还有,有什么理由说它不能在课堂上完成吗?

Ign*_*ams 11

class Point(object):
  pass

Point.ORIGIN = Point()
Run Code Online (Sandbox Code Playgroud)


Kar*_*tel 6

事后分配:

class Point:
  def __init__(self, x=0, y=0):
    self.x = x
    self.y = y


Point.ORIGIN = Point()
Run Code Online (Sandbox Code Playgroud)

  • 不,不是.**赋值**在模块级别,但**值**存储为Point类的属性. (7认同)
  • 名称“Point”直到类主体结束时才存在。 (2认同)

lqc*_*lqc 5

您不能创建类的实例,直到实际创建该类,也就是在评估类主体之后(注意:它像普通 Python 代码一样执行)。

您的 Java 示例也是如此:ClassLoader 创建Point类,然后从static字段执行代码。

Python 中类加载器的粗略等价物是元类,因此您可以执行以下操作:

def class_with_static(name, bases, body):
    static_block = body.pop("__static__", None)
    klass = type(name, bases, body)
    if static_block:
        static_block(klass)
    return klass

class Point(object):
    __metaclass__ = class_with_static

    def __static__(cls):
        cls.ORIGIN = cls()

    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

assert isinstance(Point.ORIGIN, Point)
assert Point.ORIGIN.x == Point.ORIGIN.y == 0
assert not hasattr(Point, "__static__")
Run Code Online (Sandbox Code Playgroud)

当然,这会产生其他一些后果,例如: 的所有子类都Point将拥有ORIGIN自己的属性。所以你可能只想像其他人一样去做:)

  • 你不应该发明你自己的 __static__` dunder 风格的变量,因为它们可能与未来解释器定义的“魔法”名称冲突 - 根据[命名约定](https://www.python.org/ dev/peps/pep-0008/#naming-conventions) PEP 8 的部分说:“永远不要发明这样的名称;只能按照记录使用它们。” (3认同)
  • **致未来的读者**:大多数提出这个问题的人都希望在此之后得到更简单的答案(将类变量的赋值放在其自己的语句中,在类声明之后)。 (2认同)