2017-08-13 145 views
1

我有一个基类A,以及两个子类从A继承BC,有在A一些变量都A对象之间共享,所以我选择使用类变量,这些类变量应该只初始化一次,我可以通过明确测试并设置A.some_varA中执行此操作。类变量初始化在Python3继承

的示例代码(使用显式的类名):

from queue import Queue 


class A: 
    data_queue = None 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     if A.data_queue is None: 
      A.data_queue = Queue() 


class B(A): 
    pass 


class C(A): 
    pass 


b = B() 
c = C() 

b.data_queue.put(5) 
c.data_queue.get() # Works fine 

不过,我不认为这是因为类名是个好主意可以开发过程中被改变。

我也试过type但在这样的变量都B对象或C对象之间共享,因为type(self)回报BC

from queue import Queue 


class A: 
    data_queue = None 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     if type(self).data_queue is None: 
      type(self).data_queue = Queue() 


class B(A): 
    pass 


class C(A): 
    pass 


b = B() 
c = C() 

b.data_queue.put(5) 
c.data_queue.get() # Block 

那么,有没有更好的方法来初始化类变量A没有显式类名?

+0

是否有任何理由你不只是用'data_queue = Queue()'而不是'data_queue = None'来初始化类变量? –

+0

@ robert_x44是的,我可以用'data_queue = Queue()'初始化'data_queue',但是我有另一个'Process'需要初始化,它需要'A'的基类的一些上下文信息,如果我选择在类体中初始化它,我仍然必须对类名进行硬编码以访问上下文信息(由于设计原因,我无法在'A'的基类中定义此'Process') – Time1ess

+0

'self .__ class __。data_queue'将工作。可变的类级别状态,或从_instance_构造函数延迟初始化类级别的东西,通常不是一个好主意。在类创建时初始化队列权限(是的,类体中的'data_queue = Queue()'),或者考虑其他共享机制。 – 9000

回答

0

经过一番苦苦挣扎之后,我想出了一些解决方案,尽管它不太好,但它以某种方式实现了我的目标。

解决方案1:使用装饰到基准设置为分类

例如代码:

from queue import Queue 


def cls_ref(cls): # With this decorator, cls refs its self 
    cls.cls = cls 
    return cls 


@cls_ref 
class A: 
    data_queue = None 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     cls = self.cls 
     if cls.data_queue is None: 
      cls.data_queue = Queue() 


class B(A): 
    pass 

class C(A): 
    pass 


b = B() 
c = C() 

b.data_queue.put(5) 
c.data_queue.get() # Works fine 

解决方案2:与合格的名称

根据使用惰性计算qualified name的定义:

虚线名称显示模块全局范围中的“路径”,如PEP 3155中定义的那样,该模块中定义的类,函数或方法定义为 。对于顶级函数和类,限定名称相同作为对象的名称:

>>> class C: 
...  class D: 
...   def meth(self): 
...    pass 
... 
>>> C.__qualname__ 
'C' 
>>> C.D.__qualname__ 
'C.D' 
>>> C.D.meth.__qualname__ 
'C.D.meth' 

示例代码:

from queue import Queue 


class LazyInit: 
    def __init__(self, name): 
     self.name = name 
    def __get__(self, instance, owner): 
     return globals()[self.name] 


class A: 
    cls = LazyInit(locals()['__qualname__']) 
    data_queue = None 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     cls = self.cls 
     if cls.data_queue is None: 
      cls.data_queue = Queue() 


class B(A): 
    pass 

class C(A): 
    pass 


b = B() 
c = C() 

b.data_queue.put(5) 
c.data_queue.get() # Works fine 

这两种解决方案正常工作与我,如果有其他更好的解决方案,请让我知道。 :)