2016-09-23 41 views
0

我知道我可以使用描述符來改變靜態屬性,就好像它是一個正常的屬性。但是,當我嘗試使用正常類屬性的描述符時,我最終更改了它引用的對象,而不是對象中的值。如何使用非靜態方法的描述符?

如果我有

正常使用,考慮到法(PARAM)返回一個對象

class SomeClass(): 
    property = method(param) 

那麼我可以這樣做:

instance = SomeClass() 
instance.property = 3 

,並能夠有一個設置由哪個屬性的類處理。現在

,如果我不是有

class SomeClass(): 
    def__init__(self): 
     self.property = method(param) 

和我做的:

instance = SomeClass() 
instance.property = 3 

代碼不工作,我改寫爲3提及的方法(PARAM)創建的對象而不是由描述符處理該設置。

有沒有一種方法可以在沒有靜態方法的情況下使用描述符?實質上,我需要能夠創建該類的多個實例,每個實例都具有可以使用方便的描述符方法更改的自己的獨特屬性。那可能嗎?

Python版本:2.7

謝謝!

回答

0

考慮method(param)返回一個描述符,你可以用一個屬性手動調用它像這樣:

class SomeClass(object): 

    def __init__(self): 
     self._descriptor = method(param) 

    @property 
    def my_attribute(self): 
     return self._descriptor.__get__(self, self.__class__) 

    @my_attribute.setter 
    def my_attribute(self, value): 
     self._descriptor.__set__(self, value) 

這將允許您創建實例,具體描述,而不是類級別的描述符。

我還是沒有看到你這樣做的原因,因爲描述符應該通常是類級別的。這就是他們的觀點。否則,它們只是可以使用屬性調用的常規對象。

+0

基本上,我使用硒和頁面對象來建模一個頁面。頁面對象模塊是第三方的,並使用具有靜態屬性的描述符(頁面元素作爲描述符,用戶可以使用'='運算符將文本插入到文本框中)。但是我需要能夠同時實例化多個頁面對象(2個瀏覽器瀏覽同一頁面),每個頁面都有自己的構成頁面元素的實例。所以我需要做出調整,以便利用已經構建的模塊。 謝謝,我今天晚些時候會試試你的代碼 –

1

描述符提供了一種簡單的機制,用於將方法中綁定函數的常用模式變化。

回顧一下,函數有一個__get__()方法,以便它們可以在作爲屬性訪問時轉換爲方法。非數據描述符將呼叫轉換爲f(obj, *args)。調用klass.f(*args)變成f(*args)

此圖表總結了結合和它的兩個最有用的變體:

Transformation Called from an Object Called from a Class 
function   f(obj, *args)   f(*args) 
staticmethod  f(*args)    f(*args) 
classmethod   f(type(obj), *args)  f(klass, *args) 

靜態方法返回底層函數不變化。主叫或者c.f或C.f被直接查找的等效成

object.__getattribute__(c, "f") or object.__getattribute__(C, "f"). 其結果是,功能變得從任一個對象或類相同訪問。

靜態方法的好候選方法是不引用自變量的方法。

class RevealAccess(object): 
    """A data descriptor that sets and returns values 
     normally and prints a message logging their access. 
    """ 
    def __init__(self, initval=None, name='var'): 
     self.val = initval 
     self.name = name 

    def __get__(self, obj, objtype): 
     print 'Retrieving', self.name 
     return self.val 

    def __set__(self, obj, val): 
     print 'Updating', self.name 
     self.val = val 

>>> class MyClass(object): 
...  x = RevealAccess(10, 'var "x"') 
...  y = 5 
... 
>>> m = MyClass() 
>>> m.x 
Retrieving var "x" 
10 
>>> m.x = 20 
Updating var "x" 
>>> m.x 
Retrieving var "x" 
20 
>>> m.y 
5 
+0

謝謝!我理解你演示的這個應用程序。我只是想知道,例如,x和y(在您的代碼中)是否可以是對象的屬性(可通過self。訪問),而不是類的靜態變量。你說什麼? –

0

屬性是「計算屬性」。屬性是使用描述符實現的。如果查找對象的屬性並找到描述符對象,則描述符的getter函數將計算該值。

此特殊規則僅在級別級別有效。

這就是爲什麼:

class SomeClass(): 
    property = <a property object here> 

限定一個屬性(計算屬性)對於所有SomeClass實例,但:

class SomeClass(): 
    def__init__(self): 
     self.property = <a property object here> 

定義這恰好是屬性對象類型的普通屬性,但是沒有以任何方式特別對待。它的getter和setter被忽略(當然,除非被用戶代碼明確地調用)。


沒有其他方式使用描述符和屬性來設置它們在類中而不是在實例中。

更新 - 例如:

小例子:而不是創建幾個實例各有其描述符(的做法,不工作),一個新的子類實例每次。

class BaseClass: 
    pass 

_class_number = 0 
def class_factory(prop): 
    global _class_number 
    _class_number += 1 
    return type('Class' + str(_class_number), (BaseClass,), dict(prop=prop)) 

c1 = class_factory(property(fget=lambda self: "property1"))() 
print(c1.prop) 
c2 = class_factory(property(fget=lambda self: "property2"))() 
print(c2.prop) 
0

傢伙,

感謝您的幫助。在許多偉大的建議中,我決定將集合得到方法,從而失去了描述符的實用性,同時保持了爲我完全編程的模塊的實用性。我簡單地擴展了類「PageElement」,創造了兩個新的方法get()和()設置,它調用其相對應的實現:

def get(self): 
    return self.__get__(self.owner_page, self.owner_page.__class__) 

def set(self, value): 
    self.__set__(self.owner_page, value) 

感謝您的幫助!我用我仍然不知道的語言展開了很多細節。我會繼續挖掘。

相關問題