gpt4 book ai didi

Python:使用 __getattribute__ 按名称调用实例成员的方法

转载 作者:行者123 更新时间:2023-11-28 21:30:42 24 4
gpt4 key购买 nike

我有一个包含成员对象的类。我想像调用容器类的方法一样调用成员的方法。

以下示例说明了(但在不同的上下文中)我想要做的事情。

假设我们有两个类代表两种不同类型的产品:玩具鞋子。每个类都有两个方法,比如说 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 ' 调用函数 __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)

关于Python:使用 __getattribute__ 按名称调用实例成员的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1810526/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com