2011-09-02 132 views
2

可能重复:
Can I get a reference to the 'owner' class during the init method of a descriptor?Python:类静态成员指向自己?

代码是胜过千言万语:

>>> class ShortRib(object): 
>>>  def __init__(self, owner): 
>>>   self.owner = owner 
>>> 
>>>  ... some more methods and stuff ... 
>>> 
>>> 
>>> class Cow(object): 
>>>  shortRib = ShortRib(self) 
>>> 
>>> 
>>> class BrownCow(Cow): 
>>>  pass 
>>> 
>>> BrownCow.shortRib.owner 
<class '__main__.BrownCow'> 

这是不行的,但我希望它会。基本上,我希望每个类都有一些静态/类变量(我不确定它在哪种情况下),但需要每个人都知道它属于哪个类。不幸的是,我不能在班级声明的主体中“获得”班级。当然,我总是可以用一个装饰者来做这件事:

>>> def vars(**kwargs): 
>>>  def wrap(cls):  
>>>   for k, w in kwargs.items(): 
>>>    setattr(cls, k, w(cls)) 
>>>   return cls 
>>>  return wrap 
>>> 
>>> @vars(shortRib=lambda cls: ShortRib(cls) 
>>> class BrownCow(Cow): 
>>>  ... 
>>> 
>>> BrownCow.shortRib.owner 

哪会工作。另一种方法是使类装饰器遍历所有的shortRib和类似的静态变量,并在类声明完成后设置它们的所有者。然而,这看起来像是一个令人难以置信的迂回和不直观的做法,应该是一个非常简单的操作:让一个班的静态/班级成员知道他们属于谁。

有没有一个“适当”的方式来做到这一点?

澄清:

我想这些成员属于类,而不是实例。我试图去找一个几乎是纯粹功能的风格,只使用类来继承共享行为,而不是创建它们的实例。实例会倾向于让我的函数访问所有函数共享的任意实例数据,这会破坏我尝试的纯函数。我可以使用我不触及的空实例,但我认为使用纯类会更清晰。

+0

“所有者”应该是所有者的类还是所有者对象? – tauran

+0

@Cat - 不重复。也许他需要在创建实例之前绑定'ShortRib' - '__init__'可能不够早。 – agf

+0

@agf:再次阅读。 –

回答

2

您可以轻松地做到这一点在__new__

class ShortRib(object): 
    def __init__(self, owner): 
     self.owner = owner 

class Cow(object): 
    shortRib = None 
    def __new__(cls, *args, **kwargs): 
     if cls.shortRib == None: 
      cls.shortRib = ShortRib(cls) 
     return super(Cow, cls).__new__(cls, *args, **kwargs) 

Cow() 
Cow.shortRib.owner 

甚至__init__,如果你不介意引用self.__class___

你也可以用元类做到这一点:

class ShortRib(object): 
    def __init__(self, owner): 
     self.owner = owner 

class MetaCow(type): 
    def __new__(cls, name, base, attrs): 
     attrs['shortRib'] = ShortRib(cls) 
     return super(MetaCow, cls).__new__(cls, name, base, attrs) 

class Cow(object): 
    __metaclass__ = MetaCow 

Cow.shortRib.owner 
1

为什么不让牛类的实例有牛小排,而不是类本身?:

class ShortRib(object): 
    def __init__(self,owner): 
     self.owner=owner 

class Cow(object): 
    def __init__(self): 
     self.shortRib=ShortRib(self) 

class BrownCow(Cow): 
    pass 

print(BrownCow().shortRib.owner) 
# <__main__.BrownCow object at 0xb76a8d6c> 

(否则,您将需要一个类装饰或元类 - 因为你已经提到但简单比复杂好,所以为什么不选择简单)


顺便说一句,如果你确实想改用实例类:

class ShortRib(object): 
    def __init__(self, owner): 
     self.owner = owner 

class MetaCow(type): 
    def __init__(cls, name, base, attrs): 
     super(MetaCow, cls).__init__(name, base, attrs) 
     cls.shortRib = ShortRib(cls) 

class Cow(object): 
    __metaclass__ = MetaCow 

class BrownCow(Cow): 
    pass 

print(Cow.shortRib.owner) 
# <class '__main__.Cow'> 

print(BrownCow.shortRib.owner) 
# <class '__main__.BrownCow'> 

使用

class MetaCow(type): 
    def __new__(cls, name, base, attrs): 

不正确。既然你要修改的cls,不meta属性,使用MetaCow.__init__MetaCow__new__type.__new__签名是

class MetaCow(type): 
    def __new__(meta, name, base, attrs): 

+0

这不是他所问的,他显然已经知道如何做到这一点。你也可以在没有装饰器或元类的'__init__'或'__new__'中执行。 – agf

+0

请仔细重读OP的问题。 – unutbu

+0

他的澄清再次强调他不想这样做(尽管听起来好像他正在设计错误) – agf

0

两种方法做你想要什么:

  • 可以重写__getattr__方法在任何类返回你的愿望的时候什么你问一个属性的价值。
  • 您可以使用一个属性,它有一个返回你想让它返回对象一个getter。

这两个__getattr__方法和属性都被继承。