类实例作为静态属性

时间:2016-01-01 14:28:25

标签: python class python-3.x static-methods language-design

Python 3不允许您在其体内引用类(方法除外):

class A:
    static_attribute = A()

    def __init__(self):
        ...

这会在第二行中引发NameError,因为'A' is not defined

替代品

我很快找到了一个解决方法:

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

    def __init__(self):
        ...

虽然这不完全相同,因为它每次都返回一个不同的实例(你可以通过第一次将实例保存到静态变量来防止这种情况)。

是否有更简单和/或更优雅的替代品?

修改 的 我已将有关此限制原因的问题移至separate question

4 个答案:

答案 0 :(得分:4)

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

这是一个更简单的选择:

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

A.static_attribute = A()

答案 1 :(得分:2)

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

这就是造成错误的原因:

class MyClass(object):
    a = 1 / 0

但是这不是:

def my_func():
    a = 1 / 0

A的课程定义正文中,A尚未定义,因此您无法在其定义之后引用它。< / p>

有几种方法可以完成您所要求的内容,但我不清楚为什么这样做会有用,所以如果您能提供有关您的用例的更多详细信息,它会更容易推荐哪条路走下去。

最简单的是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()

答案 2 :(得分:1)

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

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>

答案 3 :(得分:0)

您可以使用类装饰器:

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

@set_static_attribute    
class A:
    pass

现在:

>>>> A.static_attribute
<__main__.A at 0x10713a0f0>

在类的顶部应用装饰器使其比在可能的长类定义之后设置static_attribute更明确。应用的装饰者&#34;属于&#34;到类定义。因此,如果您在源代码中移动类,则更有可能移动它而不是类外的属性的额外设置。