2011-09-02 107 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__方法和屬性都被繼承。