Extending a decorated class in Python
Is it possible to extend a class which has a decorator applied to it? For example:
@someDecorator
Class foo(object):
...
...
Class bar(foo):
...
...
Ideally bar would not be affected by the decorator, but first I want to find out if this is even possible. Currently I am 开发者_如何学Gogetting a non-runtime error:
"TypeError: Error when calling the metaclass bases function() argument 1 must be code, not str "
Any suggestions?
Yes it is possible, as long as @someDecorator
is actually returning a class. A class decorator takes a class as its argument, and should almost always return a class, unless you are doing something very unusual.
foo
, in this case, will be bound to whatever @someDecorator
returns.
Is this decorator returning something else? A str
?
For anyone looking for an alternative to the chosen answer, I found best way for me was to decorate __init__
inside the class decorator. So for example:
def some_decorator(cls):
def decorate_init(func):
def decorated(*args, **kwargs):
func(*args, **kwargs) # Run __init__
instance = args[0]
# Do whatever you need with the newly constructed instance
return decorated
cls.__init__ = decorated_init(cls.__init__)
return cls
As Matt put it, your decorator is not working. Whenever you get your decorator to work properly (make some tests, even imediate tests by copying and paste to a console):
What the (valid) decorator returns is your class "foo" - you can't access what it was before the decorator being applied if you use the decorator syntax.
However, decorators in Python are a syntatic sugar to replace the following declared function or class with what is returned by processing that function or class with the decorator. Thus, these are equivalent:
@someDecorator
class foo(object):
pass
and
class foo(object):
pass
foo = someDecorator(foo)
Therefore, you can achieve the effect of extending a class before applying the decorator simply by doing:
class foo(object):
pass
class bar(foo):
pass
foo = someDecorator(foo)
精彩评论