如何布置课堂?

2024-10-01 11:37:27 发布

您现在位置:Python中文网/ 问答频道 /正文

在Python2.5中,是否有方法创建装饰类的装饰器?具体来说,我想使用decorator将成员添加到类中,并更改构造函数以获取该成员的值。

正在查找以下内容(在“类Foo:”上有语法错误):

def getId(self): return self.__id

class addID(original_class):
    def __init__(self, id, *args, **kws):
        self.__id = id
        self.getId = getId
        original_class.__init__(self, *args, **kws)

@addID
class Foo:
    def __init__(self, value1):
        self.value1 = value1

if __name__ == '__main__':
    foo1 = Foo(5,1)
    print foo1.value1, foo1.getId()
    foo2 = Foo(15,2)
    print foo2.value1, foo2.getId()

我想我真正想要的是一种在Python中实现C接口的方法。我想我需要改变我的模式。


Tags: 方法selfidfooinitdef成员装饰
3条回答

除了类修饰符是否是解决问题的正确方法之外:

在Python2.6及更高版本中,有带@-语法的类装饰器,因此您可以编写:

@addID
class Foo:
    pass

在旧版本中,您可以使用另一种方法:

class Foo:
    pass

Foo = addID(Foo)

但是请注意,这与函数decorators的工作原理相同,decorator应该返回新的(或修改过的原始)类,这不是您在示例中所做的。addID装饰器如下所示:

def addID(original_class):
    orig_init = original_class.__init__
    # Make copy of original __init__, so we can call it without recursion

    def __init__(self, id, *args, **kws):
        self.__id = id
        self.getId = getId
        orig_init(self, *args, **kws) # Call the original __init__

    original_class.__init__ = __init__ # Set the class' __init__ to the new one
    return original_class

然后,您可以为您的Python版本使用适当的语法,如上所述。

但我同意其他人的看法,如果您想重写__init__,继承更适合。

没有人解释过可以动态定义类。因此,您可以使用decorator来定义(并返回)子类:

def addId(cls):

    class AddId(cls):

        def __init__(self, id, *args, **kargs):
            super(AddId, self).__init__(*args, **kargs)
            self.__id = id

        def getId(self):
            return self.__id

    return AddId

它可以在Python 2中使用(Blckknght的注释解释了为什么您应该在2.6中继续这样做),如下所示:

class Foo:
    pass

FooId = addId(Foo)

在类似于Python 3的程序中(但是要小心在类中使用super()):

@addId
class Foo:
    pass

所以你可以让你的蛋糕吃它-继承装饰师!

我支持这样的观点,即您可能希望考虑一个子类,而不是您概述的方法。但是,不知道你的具体情况,YMMV:-)

你想的是一个元类。元类中的__new__函数被传递给类的完整定义,然后它可以在创建类之前重写该定义。那时,你可以把构造器换成一个新的构造器。

示例:

def substitute_init(self, id, *args, **kwargs):
    pass

class FooMeta(type):

    def __new__(cls, name, bases, attrs):
        attrs['__init__'] = substitute_init
        return super(FooMeta, cls).__new__(cls, name, bases, attrs)

class Foo(object):

    __metaclass__ = FooMeta

    def __init__(self, value1):
        pass

替换构造函数可能有点戏剧性,但该语言确实为这种深入的内省和动态修改提供了支持。

相关问题 更多 >