我有一个包含成员对象的类。我想将成员的方法称为容器类的方法。
以下示例说明了(但在不同的上下文中)我想要做什么。
假设我们有两个代表两种不同产品的类:玩具和鞋子。
每个类都有两个方法,比方说,weight()
和description()
,它们可以显着地返回项目的权重和项目的描述。
现在我想将这些产品放在单独的框中 - 每个框只包含一个Toy
一个Shoe
。
我希望仍然能够访问方法weight()
和description()
,但我希望它们是Box
实例的成员。另外,我不想在weight()
类中专门实现方法description()
和Box
,因为我不想在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
和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
的{{1}}',它找不到成员{{1}因此,再次无限递地调用函数__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)
,程序会再次遇到递归循环问题。有人知道为什么吗?
答案 0 :(得分:3)
您可以按照建议使用__getattr__
代替__getattribute__
。对于不存在的属性,将调用该属性。
如果您确实想要覆盖(几乎)所有属性访问权限,那么继续使用__getattribute__
并进行如此定义:
def __getattribute__(self, name):
return getattr(object.__getattribute__(self, 'product'), name)
答案 1 :(得分:2)
使用__getattr__
代替__getattribute__
。如果您使用__getattribute__
,则在评估self.product
时将获得无限递归。
__getattr__
,因此不会导致此问题。
答案 2 :(得分:1)
现在有趣的事情......如果我首先定义成员self.product,as 如上所示,该程序正常工作。但是,如果我尝试定义 首先是成员self.box_code,程序会受到递归循环的影响 问题了。有人知道为什么吗?
如果你先写self.box_code = box_code
,就会发生这种情况:
__setattr__
并尝试查找未定义的self.product
。
因为它是未定义的__getattr__
被调用来解析属性"product"
,但在__getattr__
内还有另一个self.product
会导致它成为一个递归循环。