【问题标题】:Class instance as static attribute类实例作为静态属性
【发布时间】:2016-04-06 01:10:01
【问题描述】:

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

【问题讨论】:

  • 如果您提供了一个案例,让类的实例成为同一类的属性很有用,这将是一个更有趣的问题。例如,与 Java 不同的是,您可以拥有存在于类定义之外的对象。

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


【解决方案1】:

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

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

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

A.static_attribute = A()

【讨论】:

    【解决方案2】:

    当您定义一个类时,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()
    

    【讨论】:

      【解决方案3】:

      使用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>
      

      【讨论】:

        【解决方案4】:

        你可以使用类装饰器:

        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 更明确。应用的装饰器“属于”类定义。因此,如果您在源代码中移动类,则更有可能将其移动,而不是在类外额外设置属性。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-11
          • 1970-01-01
          • 2013-08-25
          • 2017-09-05
          相关资源
          最近更新 更多