如果包装器可以替换实例方法,为什么要使用types.MethodType呢?

时间:2014-03-16 05:15:05

标签: python python-2.7 wrapper

所以如果我有一个方法foo的课程:

class A(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def foo(self):
        return "Hey I am called %s." % self.name

我决定制作一个包装器:

def bar(obj, func):
    def inner(*args, **kwargs):
        print "I am %d years old." % obj.age
        return func(*args, **Kwargs)
    return inner

稍后我会继续在obj.foo类的实例上替换A,一切都很好。

Stick = A('Stick', 32)
Stick.foo = bar(Stick, Stick.foo)
Stick.foo()
>>> I am 32 years old.
>>> Hey I am called Stick.

所以没关系,但是如果我省略return func(*args, **kwargs)位,它就好像它只是替换方法,就像使用types.MethodType替换实例方法时所期望的那样。飞。

def bar(obj):
    def inner(*args, **kwargs):
        return "I am %d years old." % obj.age
    return inner
Stick.foo = bar(Stick)
Stick.foo()
>>> I am 32 years old.

所以也许这种方式会产生某种开销,或者这种实现策略模式的其他方面存在缺陷,但......这似乎很有效。与为了编写其中包含单词types.MethodType的函数而引入self相比,我不清楚为什么导入types.MethodType比仅使用包装器更受欢迎不返回原始方法,或使用赋值语法而不是@decorator的处理方式。

我觉得我经常看到使用types库的建议,其中某人似乎想要一些类似于策略模式的东西 - 并非总是如此,但往往足以让许多用户看起来似乎忽略了Python似乎已经装备好了。正如在this speech from PyCon 2009中给出了明确的例子,这些例子促使编码人员在要求改变之前对于可能已经存在的特征“首先查看语言” - 我相信他的演讲的更多内容是针对过度编码或者出去写一个PEP,但我认为它也适用于此 - 当一个包装器需要它时,是否应该转向库?

所以,除非有一些东西使types方法更具吸引力,在这种情况下答案是显而易见的,这就是我所要求的:在哪种情况下,首选使用{ {1}}而不是像我演示的那样简单地写包装器?

1 个答案:

答案 0 :(得分:1)

您需要或想要在types模块中使用任何这种情况相当罕见,但我承认过去曾为types.ModuleType提交了子类flexmock。这个模块的主要目的主要是为你提供那些本来很难引用的类的名称,但需要注意的是,其中一些类也被dictint所知。

实际上很少需要使用这些名称来构造或子类化某些东西。那你用types.MethodType之类的东西怎么办?用它来进行内省。

假设你想编写一个自动文档生成器。也许你把你的autodoc交给有问题的模块。使用types.FunctionTypetypes.TypeTypetypes.ClassType(对于旧式类),您可以弄清楚模块中的功能和类是什么,并为每个类调用适当的文档格式化程序。对于每个类,您可以遍历其成员并使用types.MethodType从其他属性中挑选出类的方法,并在适当时记录每个类。