如何在派生的python类上操作装饰器?
Posted
技术标签:
【中文标题】如何在派生的python类上操作装饰器?【英文标题】:How to operate decorator on derived python class? 【发布时间】:2013-03-23 16:09:28 【问题描述】:我想使用装饰器对派生类做一些事情(例如注册类或其他东西)。这是我的代码:
from functools import wraps
class Basic(object):
def __init__(self):
print "Basic::init"
def myDeco(name):
# define the decorator function that acts on the actual class definition
def __decorator(myclass):
# do something here with the information
print name, myclass
# do the wrapping of the class
@wraps(myclass)
def __wrapper(*args, **kwargs):
return myclass( *args, **kwargs)
# return the actual wrapper here
return __wrapper
# return the decorator to act on the class definition
return __decorator
@myDeco("test")
class Derived(Basic):
def __init__(self):
super(Derived, self).__init__()
print "Derived::init"
instance = Derived()
这给出了以下错误:
TypeError: must be type, not function
当Derived
中的super
方法被调用时。我假设变量Derived
不再是type
,而是函数__decorator
实际上。
我需要如何更改装饰器(并且只有装饰器)才能解决此问题?
【问题讨论】:
装饰器内的装饰器 - 它自找麻烦... @JakubM.: 不,这个函数是一个装饰器工厂。这是常见的做法。@wraps
在myDeco
内?对我来说看起来很奇怪
IMO,在这种情况下,__wrapper
毫无意义。对于__decorator
,可以直接返回myclass
。
【参考方案1】:
您正在用函数替换装饰类,因此类定义失败。
具体来说,super(Derived, self).__init__()
现在将一个函数传递给super()
:
>>> super(Derived, object())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be type, not function
>>> type(Derived)
<type 'function'>
类装饰器通常会更改类,添加、删除或更改其属性,然后再次返回类对象。
您应该不将Derived
替换为新类,因为您的Derived.__init__()
按名称引用自身。用另一个类替换该名称会导致痛苦(例如无限递归)。
确实工作的示例类装饰器:
def my_deco(name):
# define the decorator function that acts on the actual class definition
def decorator(cls):
# do something here with the information
print name, cls
setattr(class, name, 'Hello world!')
# return the original, augmented class
return cls
# return the decorator to act on the class definition
return decorator
【讨论】:
【参考方案2】:您的程序中有两个错误:
from functools import wraps
class Basic(object):
def __init__(self):
print "Basic::init"
def myDeco(name):
# define the decorator function that acts on the actual class definition
def __decorator(myclass):
# do something here with the information
print name, myclass
# do the wrapping of the class
class Wrap(myclass): # error 1
realSuper = myclass # I dislike this. has anyone an other aproach
def __new__(*args, **kwargs):
return myclass.__new__(*args, **kwargs)
# return the actual wrapper here
return Wrap
# return the decorator to act on the class definition
return __decorator
@myDeco("test")
class Derived(Basic):
def __init__(self):
super(Derived.realSuper, self).__init__() # error 2
print "Derived::init"
instance = Derived()
现在给出以下输出:
test <class '__main__.Derived'>
Basic::init
Derived::init
首先你需要一个其他人指出的类。
第二个super(Derived, self).__init__()
造成了无限递归:
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
exec s
File "<string>", line 32, in <module>
File "<string>", line 28, in __init__
File "<string>", line 28, in __init__
File "<string>", line 28, in __init__
File "<string>", line 28, in __init__
原因参见下面的讨论。
【讨论】:
不,super(Derived, self)
是正确的。 Python 需要以 current 类作为起点来查找 MRO 中的下一个类。通过传入Basic
,您可以明确地skip that MRO 中的类。
请解释发生了什么错误,为什么是错误,以及如何纠正。更正后的代码本身就是一个糟糕的答案。
@Martijn Pieters 请告诉我,如果我不更改它,为什么它会在这一行中无限递归。
您的Wrap
将导致无限递归。
@User:你不能用它自己的超类替换一个类。如果您需要将类行为更改为该扩展,请使用元类。使用类装饰器只改变属性,不返回替换类。以上是关于如何在派生的python类上操作装饰器?的主要内容,如果未能解决你的问题,请参考以下文章