Python 类实例作为静态属性

Python 类实例作为静态属性,python,class,python-3.x,static-methods,language-design,Python,Class,Python 3.x,Static Methods,Language Design,Python 3不允许在类的主体内引用类(方法中除外): 这会在第二行中引发名称错误,因为未定义“a” 选择 我很快找到了一个解决办法: class A: @property @classmethod def static_property(cls): return A() def __init__(self): ... 尽管这并不完全相同,因为它每次都返回不同的实例(您可以通过第一次将实例保存到静态变量来防止这种情况) 是否有

Python 3不允许在类的主体内引用类(方法中除外):

这会在第二行中引发
名称错误
,因为未定义
“a”

选择 我很快找到了一个解决办法:

class A:
    @property
    @classmethod
    def static_property(cls):
        return A()

    def __init__(self):
        ...
尽管这并不完全相同,因为它每次都返回不同的实例(您可以通过第一次将实例保存到静态变量来防止这种情况)

是否有更简单和/或更优雅的选择

编辑: 我已将有关此限制原因的问题移动到a

表达式
a()
在定义类
a
之前无法运行。在您的第一个代码块中,
A
的定义在您尝试执行
A()
时不完整

这里有一个更简单的选择:

class A:
    def __init__(self):
        ...

A.static_attribute = A()

您可以使用类装饰器:

def set_static_attribute(cls):
    cls.static_attribute = cls()
    return cls

@set_static_attribute    
class A:
    pass
现在:

>>A.static\u属性

在类的顶部应用decorator比在潜在的长类定义之后设置
static\u属性
更显式。应用的装饰器“属于”类定义。因此,如果在源代码中移动该类,则更可能将其移动,而不是在该类外部额外设置属性

使用
属性
装饰器是一种可行的方法,但需要这样做:

class A:
    _static_attribute = None

    @property
    def static_attribute(self):
        if A._static_attribute is None:
            A._static_attribute = A()
        return A._static_attribute

    def __init__(self):
        pass

a = A()
print(a.static_attribute)  # -> <__main__.A object at 0x004859D0>
b = A()
print(b.static_attribute)  # -> <__main__.A object at 0x004859D0>
A类:
_静态属性=无
@财产
def静态_属性(自身):
如果.._static_属性为无:
A.。_static_属性=A()
返回一个.._static_属性
定义初始化(自):
通过
a=a()
打印(a.static_属性)#->
b=A()
打印(b.static_属性)#->

定义类时,Python会立即执行定义中的代码。请注意,这与定义Python编译代码但不执行代码的函数不同

这就是为什么这会产生错误:

class MyClass(object):
    a = 1 / 0
但这不会:

def my_func():
    a = 1 / 0
A
的类定义主体中,
A
尚未定义,因此在定义之后才能引用它

有几种方法可以实现您的要求,但我不清楚为什么这在第一时间会有用,因此如果您能提供有关用例的更多详细信息,就可以更容易地建议采用哪种方法

最简单的方法是khelwood发布的内容:

class A(object):
    pass
A.static_attribute = A()
因为这是修改类创建,所以使用元类可能是合适的:

class MetaA(type):
    def __new__(mcs, name, bases, attrs):
        cls = super(MetaA, mcs).__new__(mcs, name, bases, attrs)
        cls.static_attribute = cls()
        return cls


class A(object):
    __metaclass__ = MetaA
或者,您可以使用描述符延迟创建实例,或者如果您希望进一步自定义对实例的访问:

class MyDescriptor(object):
    def __get__(self, instance, owner):
        owner.static_attribute = owner()
        return owner.static_attribute


class A(object):
    static_attribute = MyDescriptor()

如果您提供了一个案例,让一个类的实例成为同一个类的属性是有用的,那么这将是一个更有趣的问题。例如,与Java不同,您可以拥有存在于类定义之外的对象。
class MetaA(type):
    def __new__(mcs, name, bases, attrs):
        cls = super(MetaA, mcs).__new__(mcs, name, bases, attrs)
        cls.static_attribute = cls()
        return cls


class A(object):
    __metaclass__ = MetaA
class MyDescriptor(object):
    def __get__(self, instance, owner):
        owner.static_attribute = owner()
        return owner.static_attribute


class A(object):
    static_attribute = MyDescriptor()