在学习Python时,通过典型的Point类示例,我注意到由于某种原因,我不能拥有与类相同类型的类级别(静态变量)。 E.g。
class Point:
ORIGIN = Point() # doesn't work
def __init__(self, x=0, y=0):
self.x = x
self.y = y
虽然在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;
}
}
问题是:在Python中是否有任何实现相同的方法。现在我依赖于模块级变量,我不喜欢那个解决方案。还有,为什么不能在课堂上做这个?
答案 0 :(得分:11)
class Point(object):
pass
Point.ORIGIN = Point()
答案 1 :(得分:6)
事后分配:
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
Point.ORIGIN = Point()
答案 2 :(得分:4)
在实际创建该类之前,您无法创建类的实例,这是在评估类主体之后(注意:它的执行方式与普通的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__")
当然这会产生一些其他后果,例如:Point
的所有子类都有自己的ORIGIN
属性。所以你可能只想像其他人那样做:)
答案 3 :(得分:2)
你可以用类装饰器做到这一点,虽然我不确定它的名字是多少。方法如下:
def add_class_var(name, *args, **kwrds):
def decorator(cls):
setattr(cls, name, cls(*args, **kwrds))
return cls
return decorator
@add_class_var('ORIGIN')
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
print Point.ORIGIN, Point.ORIGIN.x, Point.ORIGIN.y
# <__main__.Point instance at 0x00B5B418> 0 0
虽然在上面的代码中没有使用,但您也可以通过装饰器间接地将参数传递给类的__init__()
构造函数。