在Python中重定向类成员调用

1 投票
2 回答
1905 浏览
提问于 2025-04-15 18:42

我试着去“扩展”一个封闭的类。

collections.defaultdict(lambda: 1)

我想给它添加两个方法,分别叫做“vocabulary”和“wordcount”。显然,给内置类型设置属性是行不通的,我也不能从defaultdict继承,所以我决定写一个类,并把对它的调用重定向到我想要扩展的类型上。

class BagOfWordDoc():
    def __init__(self):
        self.data = collections.defaultdict(lambda: 1)
        for method in dir(self.data):
            if hasattr(getattr(self.data, method),'__call__') and method not in ['__class__', '__self__']:
                l = lambda *args: getattr(self.data, method)(*args)
                setattr(self, method,l)

    def vocabulary(self):
        return self.data.keys()

    def wordcount(self):
        return reduce(operator.add, self.data.values(), 0) 

但是在访问它的时候出现了问题。

 doc = BagOfWordDoc()
 doc[123]   = 123          # yields TypeError: values() takes no arguments (1 given)
 doc.keys()                # yields TypeError: values() takes no arguments (1 given)
 doc.xxx()                 # yields TypeError: values() takes no arguments (1 given)

所以就好像每个lambda函数都被映射到了“values”这个函数上,而“values”是属性列表中的最后一个元素。

你知道为什么会这样吗?至于最开始的问题,我现在在考虑重写我自己的defaultdict。

更新

根据建议,这里是可用的实现:

class BagOfWordDoc():
    def __init__(self):
        self.data = collections.defaultdict(lambda: 0)

    def __getattr__(self, *args):
        return self.data.__getattribute__(*args)

    def vocabulary(self):
        return self.data.keys()

    def wordcount(self):
        return reduce(operator.add, self.data.values(), 0) 

2 个回答

1

你说的“不能从defaultdict继承”是什么意思呢?对我来说是可以的(虽然这个例子不是很好,但我不太确定你想要实现什么,所以…):

#!/usr/bin/env python


from collections import defaultdict
import operator


class DD(defaultdict):

   def vocabulary(self):
        return self.keys()

    def wordcount(self):
        return reduce(operator.add, self.data.itervalues(), 0)


if __name__ == '__main__':
    dd = DD(int)

    dd[2] += 1
    print dd.vocabulary()
4

要么是从一个类复制到另一个类,而不是从一个实例复制到另一个实例,要么就让 .__getattr__() 去调用被封装的对象。

撰写回答