[英]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.