2013-07-03 70 views
0

我在python中有這個一般問題。基類定義了一個類屬性class_attr。這個屬性是不可變的,在這種情況下它是一個數字。我想從派生類中更改此屬性,從而將Base.class_attr重新綁定爲新值(在我的玩具案例中,將其遞增)。從派生類中重新綁定基類中的不可變類屬性

問題是如何在沒有明確命名Base的語句Base.class_attr += 1中這樣做。

class Base(object): 
    # class attribute: 
    class_attr = 0 

class Derived(Base): 
    @classmethod 
    def increment_class_attr(cls):   
     Base.class_attr += 1 
     # is there a solution which does not name the owner of the 
     # class_attr explicitly? 

     # This would cause the definition of Derived.class_attr, 
     # thus Base.class_attr and Derived.class_attr would be 
     # two independent attributes, no more in sync: 
    # cls.class_attr += 1 

Derived.increment_class_attr() 
Derived.increment_class_attr() 

print Base.class_attr # 2 

請注意:我是非常的問題後,也就是我可以重新綁定一個父類的屬性。我並沒有解決這個問題的解決方法(例如,將increment_class_attr轉移到基地)。

回答

1

使用__bases__屬性:

In [68]: class Base(object): 
    ...:  # class attribute: 
    ...:  class_attr = 0 
    ...:  

In [69]: class Derived(Base): 
    ...:  @classmethod 
    ...:  def inc(cls): 
    ...:   p, = cls.__bases__ 
    ...:   p.class_attr += 1 
    ...:   

In [70]: Base.class_attr 
Out[70]: 0 

In [71]: Derived.inc() 

In [72]: Derived.inc() 

In [73]: Base.class_attr 
Out[73]: 2 

如果你有多重繼承:

In [88]: class DifferentInherited(object): 
    ...:  class2_attr = 0 
    ...: 


In [90]: class Der2(Base, DifferentInherited): 
    ...:  @classmethod 
    ...:  def inc(cls): 
    ...:   print cls.__bases__ 
    ...:   a, b, = cls.__bases__ 
    ...:   print a.class_attr 
    ...:   print b.class2_attr 
    ...:   

In [91]: Der2.inc() 
(<class '__main__.Base'>, <class '__main__.DifferentInherited'>) 
2 
0 

假設你不知道繼承順序要麼,你就需要測試每個類的變量:

In [127]: class Der3(DifferentInherited, Base): 
    ...:  @classmethod 
    ...:  def inc(cls): 
    ...:   # This gets a list of *all* classes with the attribute `class_attr` 
    ...:   classes = [c for c in cls.__bases__ if 'class_attr' in c.__dict__] 
    ...:   for c in classes: 
    ...:    c.class_attr += 1 
    ...:    

In [128]: Der3.inc() 

In [129]: Base.class_attr 
Out[129]: 3 

In [131]: DifferentInherited.class2_attr 
Out[131]: 0 

和多重繼承使用__mro__

In [146]: class Multi(Der3): 
    ...:  @classmethod 
    ...:  def inc(cls): 
    ...:   c_attr = [c for c in cls.__mro__ if 'class_attr' in c.__dict__] 
    ...:   print c_attr 
    ...:   c_attr[0].class_attr += 1 
    ...:   

In [147]: Multi.inc() 
[<class '__main__.Base'>] 

In [148]: Base.class_attr 
Out[148]: 4 
+0

謝謝,但這與具有'Base'的原始版本具有大致相同的可維護性級別。如果我繼承Derived multiply'Derived(AnotherBase,Base)'或跨多個單繼承Derived1(Base)'; '派生(Derived1)'? – ondrejdee

+0

'__bases__'和'Base'沒有什麼共同之處。 '__bases__'指的是繼承的類。它返回一個類的元組:'p,= cls .__ bases__'獲得第一個(第一個繼承的類 - 在本例中爲'Base'。 – TyrantWave

+0

是的,我理解你的代碼。我說的是當我有另一個基類名爲'AnotherBase'並且聲明派生類'派生類(AnotherBase,Base)',那麼你的''p''變量將不再指'基',而是'AnotherBase'。但AnotherBase不是類的所有者屬性'class_attr'。類似地,通過鏈式繼承,'p'將引用'Derived1',而不是'Derived'. – ondrejdee

相關問題