首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Python:使用__getattribute__按名称调用实例成员的方法

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

Stack Overflow用户
提问于 2009-11-27 20:22:31
回答 3查看 3.3K关注 0票数 2

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

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

假设我们有两个类代表两种不同的产品:ToysShoes。每个类都有两个方法,比方说,weight()description(),它们明显地返回项的权重和项的描述。

现在,我想将这些产品放在单独的框中,-每个框将包含单个Toy或单个Shoe

我仍然希望能够访问weight()description()方法,但是我希望它们成为Box实例的成员。另外,我不希望具体实现weight()description()类中的方法,因为每当向Toy和Shoe添加新方法时,我都不希望在Box类中实现更多的方法。

下面是一个让我高兴的“最终结果”的例子:

代码语言:javascript
运行
复制
# 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

我的实现理念是这样的。

代码语言:javascript
运行
复制
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,将来我可能希望在ToyShoes中添加新的方法(例如,促进代码或其他什么),而不必修改类Box

好了,伙计们,我急切地等待你们的答复。

更新:感谢Interjay和Mike的帮助,回答问题。

我只需用__getattribute__替换Box类中的方法__getattr__,它就像Interjay所建议的那样工作得很好。类框的修正定义是:

代码语言:javascript
运行
复制
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方法的问题后,我注意到当我想设置一个属性时,我的类没有达到我想要的行为。例如,如果我尝试:

代码语言:javascript
运行
复制
box1.desc = 'plastic sword'

没有更改product1的描述(它是在box1中封装的),而是在box1中创建了一个名为"desc“的新成员。为了解决这个问题,我必须定义__setattr__函数,如下所示:

代码语言:javascript
运行
复制
def __setattr__(self, name, value):
    setattr(self.product, name, value)

但是,仅仅添加这个函数就会创建一个递归调用,因为在__init__中,我尝试分配self.product = product‘,它调用函数__setattr__,函数__setattr__找不到成员self.product,所以再次调用函数__setattr__,递归地无限调用。

为了避免这个问题,我必须更改__init__方法,以便使用类的字典分配新成员。然后,类Box的完整定义是:

代码语言:javascript
运行
复制
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,程序再次遇到递归循环问题。有人知道为什么吗?

EN

Stack Overflow用户

回答已采纳

发布于 2009-11-27 20:34:02

使用__getattr__而不是__getattribute__。如果使用__getattribute__,则在计算self.product时将得到无限递归。

只有在没有找到属性时才调用__getattr__,因此不会导致这种情况。

票数 2
EN
查看全部 3 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1810526

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档