簡體   English   中英

Python:使用__getattribute__按名稱調用實例成員的方法

[英]Python: Calling a method of an instance's member by name using __getattribute__

我有一個包含成員對象的類。 我想稱呼成員的方法,就像它們是容器類的方法一樣。

以下示例說明了(但是在不同的上下文中)我想做什么。

假設我們有兩個類代表兩種不同的產品: 玩具鞋子 每個類都有兩個方法,比方說weight()description() ,它們明顯地返回了商品的重量和商品的描述。

現在,我想將這些產品放在單獨的盒子中 -每個盒子將包含一個Toy或一個Shoe

我希望仍然能夠訪問方法weight()description() ,但是我希望它們成為Box實例的成員。 另外,我不想在Box類中專門實現方法weight()description() ,因為每當向Toy and Shoe中添加新方法時,我都不想在Box類中實現更多方法。 。

這是使我高興的“最終結果”的示例:

# Define our products
product1 = Toy('plastic gun', 200)
product2 = Shoe('black leather shoes', 500)

# Now place them in boxes
box1 = Box(product1, box_code='A1234')
box2 = Box(product2, box_code='V4321')

# I want to know the contents of the boxes
box1.description()
box2.description()

# Desired results
>> plastic gun
>> black leather shoes

我的實現思路是這樣的。

class Product():
    def __init__(self, description, weight):
        self.desc = description
        self.wght = weight

    def description(self):
        return self.desc

    def weight(self):
        return self.weight

class Toy(Product):
    pass

class Shoe(Product):
    pass

class Box(object):
    def __init__(self, product, box_code):
        self.box_code = box_code
        self.product = product

    def __getattribute__(self, name):
        # Any method that is accessed in the Box instance should be replaced by
        # the correspondent method in self.product 
        return self.product.__getattribute__(name)

但是,這不起作用! 如果運行第一個代碼塊中所示的“所需”示例,則會得到無限遞歸。 那么,如何優雅地做到這一點呢?

請注意, Box有其自己的參數box_code ,並且將來我可能想向Toy and Shoes添加新方法(例如,促銷代碼等),而不必修改Box類。

好的,我很期待您的回復。


更新 :對問題的解答感謝Interjay和Mike Boer的幫助。

我只需要用__getattribute__代替類Box__getattr__方法的定義,就可以像Interjay所建議的那樣完美地工作。 Box類的正確定義是:

class Box(object):
    def __init__(self, product, box_code):
        self.box_code = box_code
        self.product = product

    def __getattr__(self, name):
        # Any method that is accessed in the Box instance should be replaced by
        # the correspondent method in self.product 
        return self.product.__getattribute__(name)

更新 :使用__setattr__完成示例

在使用getattr方法糾正問題之后,我注意到當我想要設置屬性時,我的類沒有所需的行為。 例如,如果我嘗試過:

box1.desc = 'plastic sword'

無需更改product1的說明(該說明封裝在box1中),而是在box1中創建了一個名為“ desc”的新成員。 為了解決這個問題,我必須定義__setattr__函數,如下所示:

def __setattr__(self, name, value):
    setattr(self.product, name, value)

但是,僅添加此函數會創建一個遞歸調用,因為在__init__我嘗試分配self.product = product ,該調用函數__setattr__ ,但找不到成員self.product ,因此再次調用該函數__setattr__ ,以遞歸方式進行無窮大調用。

為了避免此問題,我必須更改__init__方法,以便使用類的字典分配新成員。 然后, Box類的完整定義是:

class Box(object):
    def __init__(self, product, box_code):
        self.__dict__['product'] = product
        self.box_code = box_code

    def __getattr__(self, name):
        # Any method that is accessed in the Box instance should be replaced by
        # the correspondent method in self.product 
        return getattr(self.product, name)

    def __setattr__(self, name, value):
        setattr(self.product, name, value)

現在有趣的是...如果首先定義成員self.product ,如上所示,該程序將正常運行。 但是,如果我嘗試首先定義成員self.box_code ,則程序將再次遭受遞歸循環問題。 有人知道為什么嗎?

您可以使用__getattr__代替__getattribute__如建議的那樣。 對於不存在的屬性的任何屬性訪問都將調用該方法。

如果確實要覆蓋(幾乎)所有屬性訪問權限,請繼續使用__getattribute__並對其進行定義:

def __getattribute__(self, name):
    return getattr(object.__getattribute__(self, 'product'), name)

使用__getattr__代替__getattribute__ 如果使用__getattribute__ ,則在評估self.product時將獲得無限遞歸。

__getattr__僅在找不到屬性的情況下才被調用,因此不會導致這種情況。

現在有趣的是...如果我首先定義成員self.product,如上所示,該程序將正常運行。 但是,如果我嘗試首先定義成員self.box_code,則該程序將再次遇到遞歸循環問題。 有人知道為什么嗎?

如果首先編寫self.box_code = box_code ,則會發生以下情況:

__setattr__被調用並嘗試查找未定義的self.product 因為它是未定義的,所以調用__getattr__來解析屬性"product"但是在__getattr__內存在另一個self.product ,這使其成為遞歸循環。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM