2011-08-31 62 views
4

在Python中,如何在類語句中獲取對當前類對象的引用?例如:我已經註銷如何獲取當前類對象的引用?

 
def setup_class_members(cls, prefix): 
    setattr(cls, prefix+"_var1", "hello") 
    setattr(cls, prefix+"_var2", "goodbye") 

class myclass(object): 
    setup_class_members(cls, "coffee") # How to get "cls"? 

    def mytest(self): 
     print(self.coffee_var1) 
     print(self.coffee_var2) 

x = myclass() 
x.mytest() 

>>> hello 
>>> goodbye 


替代品有:

  1. 使用locals():這給出了可以寫入到一個類聲明的字典。這似乎適用於類,但文檔告訴你不要這樣做。 (如果有人能向我保證這會繼續工作一段時間,我可能會試着採用這種方法)。

  2. class聲明之後向類對象添加成員:我的實際應用是派生一個PyQt4 QWidget類具有動態創建的pyqtProperty類屬性。 QWidget是不尋常的,因爲它有一個自定義的元類。非常粗略地說,元類編譯一個pyqtProperties的列表並將其存儲爲額外的成員。因此,創建後添加到類中的屬性不起作用。一個例子來清除此設置:

 
from PyQt4 import QtCore, QtGui 


# works 
class MyWidget1(QtGui.QWidget): 
    myproperty = QtCore.pyqtProperty(int) 


# doesn't work because QWidget's metaclass doesn't get to "compile" myproperty 
class MyWidget2(QtGui.QWidget): 
    pass 
MyWidget2.myproperty = QtCore.pyqtProperty(int) 

請注意,以上將用於大多數編程情況下工作;我的情況恰好是這些不尋常的角落案件之一。

+0

mouad的答案絕對是一個必須解決的問題,但要描述發生了什麼:類定義只是在它自己的本地範圍內執行一系列語句。一旦完成後,類名,基類的列表,並且將所得的dict當地人被傳遞到[類型構造](http://docs.python.org/library/functions.html#type)爲'類型( class_name,bases_tuple,locals_dict),然後返回'cls'。因此,'cls'在你想要的位置不可用,只有在之後。此外,使用元類將導致它被調用來代替'type',並且具有相同的簽名。 –

+0

我不知道這事'當地人()'把戲班工作。有趣的一點瑣事。 :-) – kindall

回答

3

AFAIK有兩路做你想要什麼:

  1. 使用metaclass,這將創造一流的創建時間的兩個變量(我認爲這是你想要的):

    class Meta(type): 
        def __new__(mcs, name, bases, attr): 
         prefix = attr.get("prefix") 
         if prefix: 
          attr[prefix+"_var1"] = "hello" 
          attr[prefix+"_var2"] = "goodbye" 
    
         return type.__new__(mcs, name, bases, attr) 
    
    class myclass(object): 
        __metaclass__ = Meta 
        prefix = "coffee" 
    
        def mytest(self): 
         print(self.coffee_var1) 
         print(self.coffee_var2) 
    
  2. 在實例化時創建你的兩個類變量:

    MyClass類(對象): PREFIX = 「咖啡」

    def __init__(self):  
        setattr(self.__class__, self.prefix+"_var1", "hello") 
        setattr(self.__class__, self.prefix+"_var2", "goodbye") 
    
    def mytest(self): 
        print(self.coffee_var1) 
        print(self.coffee_var2) 
    

N.B:我不知道你想達到的,因爲如果你要取決於prefix變量爲什麼你喜歡訪問你在mytest方法做,以創建動態的變量是什麼?!我希望這只是一個例子。

+0

我不知道爲什麼代碼的格式不爲我工作?! – mouad

+0

是的,例子很傻。這個解決方案看起來很有希我沒有提到我使用的Python 3似乎有不同的元類支持。計算出現在的差異...... – goertzenator

2

對於Python 3,類必須被聲明爲

class myclass(object, metaclass = Meta): 
    prefix = "coffee" 
    ... 


其他一些要點:

  • 元類可以是一個可調用的,而不是僅僅一個類(Python的2 & 3)

  • 如果基類的類已經有一個非標準元類,你必須確保你怎麼稱呼它是__init__()__new__()方法,而不是類型的。

  • 類語句接受被傳遞給元類關鍵字參數(Python的3只)

使用所有上述是在Python 3 mouad的解決方案的一個重寫...

def MetaFun(name, bases, attr, prefix=None): 
    if prefix: 
     attr[prefix+"_var1"] = "hello" 
     attr[prefix+"_var2"] = "goodbye" 

    return object.__class__(name, bases, attr) 

class myclass(object, metaclass = MetaFun, prefix="coffee"): 
    def mytest(self): 
     print(self.coffee_var1) 
     print(self.coffee_var2) 
+0

+1,用於將我最初的答案移植到python 3中,並教給我元類可以是任何可調用的(我不知道),順便說一句,我們應該稱之爲「元類函數或元函數;-),除此之外,如果我可能還有一些說法(問題):1.如果您正在爲python 3編寫代碼,則不需要從'object'明確地繼承'class myclass(metaclass =爲什麼你要調用'object .__ class__'而不是'type(...)'這當然是一樣的,但我更喜歡最新的只是想知道:) – mouad

+0

@mouad:你是對的,我可以把'object'當作基礎類。 2.在我的實際應用中,基類('PyQt4.QtGui.QWidget')的元類有* not *'type',當我使用'type'時給我一個錯誤。通過使用'object .__ class__',我正在說明如何檢索實際的基類元類。 – goertzenator

2

您可能使用的另外兩種方法:

類裝飾器。

def setup_class_members(prefix): 

    def decorator(cls): 
     setattr(cls, prefix+"_var1", "hello") 
     setattr(cls, prefix+"_var2", "goodbye") 
     return cls 

    return decorator 

@setup_class_members("coffee") 
class myclass(object): 
    # ... etc 

特別是如果你需要在不同的組合中添加屬性,因爲它沒有繼承任何作用的裝飾方法是很好的。

如果你正在處理一個小套的,你想以各種方式相結合的屬性,你可以使用混入類。 mixin類是一個普通類,它只是爲了將各種屬性「混合」到其他類中。

class coffee_mixin(object): 
    coffee_var1 = "hello" 
    coffee_var2 = "goodbye" 

class tea_mixin(object): 
    tea_var1 = "good morning old bean" 
    tea_var2 = "pip pip cheerio" 

class myclass(coffee_mixin, tea_mixin): 
    # ... etc 
+0

+1,對於裝飾者的方法,爲什麼我沒有考慮它:) – mouad

相關問題