I have a bunch of methods somewhere, already defined. I want a class to just be a collection of those methods.
def _a(self):
pass
def _b(self):
pass
#decorated()
class MyClass(object):
a = _a
b = _b
The decorator is written by someone else, and it does some analysis on the class immediately.
What I want is to stick those methods on the class, but they need to be on there before the decorator does its magic.
methods = { 'a': _a, 'b': _b }
#decorated(...)
class MyClass(object):
for name, impl in methods
# What goes here?
How can I do this. I assume it's some form of setattr(), but how do I get the target when it's the class I'm currently building?
Update
Current experiment is:
def merged(method_dict):
def _impl(cls):
for name, impl in method_dict.iteritems():
setattr(cls, name, impl)
return cls
return _impl
#decorated(...)
#merged(methods)
class MyClass(object):
c = _c
pass
The decorated decorator is reporting that it sees c, but not a or b
The problem is that as soon as your class is defined, it is immediately getting decorated, as you use the # syntax. Some alternatives are to go the way jonrsharpe and Ashwini Chaudhary suggested.
Also, another way you can do the thing, is wrapping the decorator into your custom one, where you will do your stuff and then only, manually decorate with the provided one, like this:
def your_decorator(func):
# your stuff
return decorated(func)
#your_decorator
class MyClass():
# ...
I'd go with what jonrsharpe suggested in the comments section: Instead of decorating the class using the # syntax, which decorates the class immediately after it's created, you should decorate it manually afterwards:
class MyClass:
pass
def _method_to_add_later(self):
pass
MyClass.method_to_add_later = _method_to_add_later
MyClass = decorated(...)(MyClass)
For example, may be right
def decorator(fn):
def _fn(*args, **kwargs):
print "Decorator"
fn(*args, **kwargs)
return _fn
#decorator
class MyClass(object):
def __init__(self):
print "Init"
def _a():
print "a"
def _b():
print "b"
if __name__ == '__main__':
methods = { 'a': _a, 'b': _b }
my = decorator(MyClass())
for name in methods:
setattr(my, name, methods[name])
my.a()
my.b()
Out:
Decorator
Init
a
b
Related
When creating a simple object hierarchy in Python, I'd like to be able to invoke methods of the parent class from a derived class. In Perl and Java, there is a keyword for this (super). In Perl, I might do this:
package Foo;
sub frotz {
return "Bamf";
}
package Bar;
#ISA = qw(Foo);
sub frotz {
my $str = SUPER::frotz();
return uc($str);
}
In Python, it appears that I have to name the parent class explicitly from the child.
In the example above, I'd have to do something like Foo::frotz().
This doesn't seem right since this behavior makes it hard to make deep hierarchies. If children need to know what class defined an inherited method, then all sorts of information pain is created.
Is this an actual limitation in python, a gap in my understanding or both?
Use the super() function:
class Foo(Bar):
def baz(self, **kwargs):
return super().baz(**kwargs)
For Python < 3, you must explicitly opt in to using new-style classes and use:
class Foo(Bar):
def baz(self, arg):
return super(Foo, self).baz(arg)
Python also has super as well:
super(type[, object-or-type])
Return a proxy object that delegates method calls to a parent or sibling class of type.
This is useful for accessing inherited methods that have been overridden in a class.
The search order is same as that used by getattr() except that the type itself is skipped.
Example:
class A(object): # deriving from 'object' declares A as a 'new-style-class'
def foo(self):
print "foo"
class B(A):
def foo(self):
super(B, self).foo() # calls 'A.foo()'
myB = B()
myB.foo()
ImmediateParentClass.frotz(self)
will be just fine, whether the immediate parent class defined frotz itself or inherited it. super is only needed for proper support of multiple inheritance (and then it only works if every class uses it properly). In general, AnyClass.whatever is going to look up whatever in AnyClass's ancestors if AnyClass doesn't define/override it, and this holds true for "child class calling parent's method" as for any other occurrence!
Python 3 has a different and simpler syntax for calling parent method.
If Foo class inherits from Bar, then from Bar.__init__ can be invoked from Foo via super().__init__():
class Foo(Bar):
def __init__(self, *args, **kwargs):
# invoke Bar.__init__
super().__init__(*args, **kwargs)
Many answers have explained how to call a method from the parent which has been overridden in the child.
However
"how do you call a parent class's method from child class?"
could also just mean:
"how do you call inherited methods?"
You can call methods inherited from a parent class just as if they were methods of the child class, as long as they haven't been overwritten.
e.g. in python 3:
class A():
def bar(self, string):
print("Hi, I'm bar, inherited from A"+string)
class B(A):
def baz(self):
self.bar(" - called by baz in B")
B().baz() # prints out "Hi, I'm bar, inherited from A - called by baz in B"
yes, this may be fairly obvious, but I feel that without pointing this out people may leave this thread with the impression you have to jump through ridiculous hoops just to access inherited methods in python. Especially as this question rates highly in searches for "how to access a parent class's method in Python", and the OP is written from the perspective of someone new to python.
I found:
https://docs.python.org/3/tutorial/classes.html#inheritance
to be useful in understanding how you access inherited methods.
Here is an example of using super():
#New-style classes inherit from object, or from another new-style class
class Dog(object):
name = ''
moves = []
def __init__(self, name):
self.name = name
def moves_setup(self):
self.moves.append('walk')
self.moves.append('run')
def get_moves(self):
return self.moves
class Superdog(Dog):
#Let's try to append new fly ability to our Superdog
def moves_setup(self):
#Set default moves by calling method of parent class
super(Superdog, self).moves_setup()
self.moves.append('fly')
dog = Superdog('Freddy')
print dog.name # Freddy
dog.moves_setup()
print dog.get_moves() # ['walk', 'run', 'fly'].
#As you can see our Superdog has all moves defined in the base Dog class
There's a super() in Python too. It's a bit wonky, because of Python's old- and new-style classes, but is quite commonly used e.g. in constructors:
class Foo(Bar):
def __init__(self):
super(Foo, self).__init__()
self.baz = 5
I would recommend using CLASS.__bases__
something like this
class A:
def __init__(self):
print "I am Class %s"%self.__class__.__name__
for parentClass in self.__class__.__bases__:
print " I am inherited from:",parentClass.__name__
#parentClass.foo(self) <- call parents function with self as first param
class B(A):pass
class C(B):pass
a,b,c = A(),B(),C()
If you don't know how many arguments you might get, and want to pass them all through to the child as well:
class Foo(bar)
def baz(self, arg, *args, **kwargs):
# ... Do your thing
return super(Foo, self).baz(arg, *args, **kwargs)
(From: Python - Cleanest way to override __init__ where an optional kwarg must be used after the super() call?)
There is a super() in python also.
Example for how a super class method is called from a sub class method
class Dog(object):
name = ''
moves = []
def __init__(self, name):
self.name = name
def moves_setup(self,x):
self.moves.append('walk')
self.moves.append('run')
self.moves.append(x)
def get_moves(self):
return self.moves
class Superdog(Dog):
#Let's try to append new fly ability to our Superdog
def moves_setup(self):
#Set default moves by calling method of parent class
super().moves_setup("hello world")
self.moves.append('fly')
dog = Superdog('Freddy')
print (dog.name)
dog.moves_setup()
print (dog.get_moves())
This example is similar to the one explained above.However there is one difference that super doesn't have any arguments passed to it.This above code is executable in python 3.4 version.
In this example cafec_param is a base class (parent class) and abc is a child class. abc calls the AWC method in the base class.
class cafec_param:
def __init__(self,precip,pe,awc,nmonths):
self.precip = precip
self.pe = pe
self.awc = awc
self.nmonths = nmonths
def AWC(self):
if self.awc<254:
Ss = self.awc
Su = 0
self.Ss=Ss
else:
Ss = 254; Su = self.awc-254
self.Ss=Ss + Su
AWC = Ss + Su
return self.Ss
def test(self):
return self.Ss
#return self.Ss*4
class abc(cafec_param):
def rr(self):
return self.AWC()
ee=cafec_param('re',34,56,2)
dd=abc('re',34,56,2)
print(dd.rr())
print(ee.AWC())
print(ee.test())
Output
56
56
56
In Python 2, I didn't have a lot luck with super(). I used the answer from
jimifiki on this SO thread how to refer to a parent method in python?.
Then, I added my own little twist to it, which I think is an improvement in usability (Especially if you have long class names).
Define the base class in one module:
# myA.py
class A():
def foo( self ):
print "foo"
Then import the class into another modules as parent:
# myB.py
from myA import A as parent
class B( parent ):
def foo( self ):
parent.foo( self ) # calls 'A.foo()'
class department:
campus_name="attock"
def printer(self):
print(self.campus_name)
class CS_dept(department):
def overr_CS(self):
department.printer(self)
print("i am child class1")
c=CS_dept()
c.overr_CS()
If you want to call the method of any class, you can simply call Class.method on any instance of the class. If your inheritance is relatively clean, this will work on instances of a child class too:
class Foo:
def __init__(self, var):
self.var = var
def baz(self):
return self.var
class Bar(Foo):
pass
bar = Bar(1)
assert Foo.baz(bar) == 1
class a(object):
def my_hello(self):
print "hello ravi"
class b(a):
def my_hello(self):
super(b,self).my_hello()
print "hi"
obj = b()
obj.my_hello()
This is a more abstract method:
super(self.__class__,self).baz(arg)
While defining a class, I need to set a global function (say, abc) as default arg value on a method. Usually, its just trivial to refer to them as abc.
But problem here is that abc is itself set as a classmethod on that class. So, the
usual soln doesnt work as abc refers to "abc, the classmethod" during class definition when "abcd" is being created. One soln might be to re-order things such that the classmethod defn. comes at the last, but I need a sure-shot (order-agnostic) way of refering to the global abc there.
There is only one crude way of doing it, that I know of, using globals()["abc"]. I want to know if theres a better way of tackling this problem.
def abc(cls,a=1):
print a+1
class A(object):
abc=classmethod(abc)
#classmethod
def abcd(cls,func=abc):
pass
from inspect import getargspec
getargspec(A.abcd).defaults[0] #should be "abc" the function, not "abc" classmethod
Possible (but not so good ?) soln
def abcd(cls,func=globals()["abc"])
Edit:
Also, do you think globals() is quite slow?
Wrap abc and similar use case options in their own namespace, like so
class A:
#staticmethod
def abc(cls, *args, **kwargs):
pass
Then you can refer to them cleanly
class Foo:
abc = classmethod(A.abc)
#classmethod
def abcd(cls, fn=A.abc):
pass
And order is not important.
You could also consider these workarounds:
Avoid name collisions:
def _abc(cls, *args, **kwargs):
pass
class Foo:
abc = classmethod(_abc)
#classmethod
def abcd(cls, fn=_abc):
pass
Do all affected defs outside of class:
def abc(cls, *args, **kwargs):
pass
def abcd(cls, fn=abc):
pass
class Foo:
abc = classmethod(abc)
abcd = classmethod(abcd)
Here's a way:
def abc(cls,a=1):
print a+1
class A(object):
#classmethod
def abcd(cls,func=abc):
pass
A.abc=classmethod(abc)
It's up to you whether this is "better" than using globals.
I would like to create a class in Python that manages above all static members. These members should be initiliazed during definition of the class already. Due to the fact that there will be the requirement to reinitialize the static members later on I would put this code into a classmethod.
My question: How can I call this classmethod from inside the class?
class Test():
# static member
x = None
# HERE I WOULD LOVE TO CALL SOMEHOW static_init!
# initialize static member in classmethod, so that it can be
#reinitialized later on again
#classmethod
def static_init(cls):
cls.x = 10
Any help is appreciated!
Thanks in advance,
Volker
At the time that x=10 is executed in your example, not only does the class not exist, but the classmethod doesn't exist either.
Execution in Python goes top to bottom. If x=10 is above the classmethod, there is no way you can access the classmethod at that point, because it hasn't been defined yet.
Even if you could run the classmethod, it wouldn't matter, because the class doesn't exist yet, so the classmethod couldn't refer to it. The class is not created until after the entire class block runs, so while you're inside the class block, there's no class.
If you want to factor out some class initialization so you can re-run it later in the way you describe, use a class decorator. The class decorator runs after the class is created, so it can call the classmethod just fine.
>>> def deco(cls):
... cls.initStuff()
... return cls
>>> #deco
... class Foo(object):
... x = 10
...
... #classmethod
... def initStuff(cls):
... cls.x = 88
>>> Foo.x
88
>>> Foo.x = 10
>>> Foo.x
10
>>> Foo.initStuff() # reinitialize
>>> Foo.x
88
You call a class method by appending the class name likewise:
class.method
In your code something like this should suffice:
Test.static_init()
You could also do this:
static_init(Test)
To call it inside your class, have your code do this:
Test.static_init()
My working code:
class Test(object):
#classmethod
def static_method(cls):
print("Hello")
def another_method(self):
Test.static_method()
and Test().another_method() returns Hello
You can't call a classmethod in the class definition because the class hasn't been fully defined yet, so there's nothing to pass the method as its first cls argument...a classic chicken-and-egg problem. However you can work around this limitation by overloading the __new__() method in a metaclass, and calling the classmethod from there after the class has been created as illustrated below:
class Test(object):
# nested metaclass definition
class __metaclass__(type):
def __new__(mcl, classname, bases, classdict):
cls = type.__new__(mcl, classname, bases, classdict) # creates class
cls.static_init() # call the classmethod
return cls
x = None
#classmethod
def static_init(cls): # called by metaclass when class is defined
print("Hello")
cls.x = 10
print Test.x
Output:
Hello
10
After re-reading your question carefully this time I can think of two solutions. The first one is to apply the Borg design pattern. The second one is to discard the class method and use a module level function instead. This appears to solve your problem:
def _test_static_init(value):
return value, value * 2
class Test:
x, y = _test_static_init(20)
if __name__ == "__main__":
print Test.x, Test.y
Old, incorrect answer:
Here's an example, I hope it helps:
class Test:
x = None
#classmethod
def set_x_class(cls, value):
Test.x = value
def set_x_self(self):
self.__class__.set_x_class(10)
if __name__ == "__main__":
obj = Test()
print Test.x
obj.set_x_self()
print Test.x
obj.__class__.set_x_class(15)
print Test.x
Anyway, NlightNFotis's answer is a better one: use the class name when accessing the class methods. It makes your code less obscure.
This seems like a reasonable solution:
from __future__ import annotations
from typing import ClassVar, Dict
import abc
import string
class Cipher(abc.ABC):
#abc.abstractmethod
def encrypt(self, plaintext: str) -> str:
pass
#abc.abstractmethod
def decrypt(self, ciphertext: str) -> str:
pass
class RotateCipher(Cipher, abc.ABC):
#staticmethod
def rotate(n: int) -> str:
return string.ascii_uppercase[n:] + string.ascii_uppercase[:n]
class VigenereCipher(RotateCipher):
_TABLE: ClassVar[Dict[str, str]] = dict({(chr(i + ord("A")), RotateCipher.rotate(i)) for i in range(26)})
def encrypt(self, plaintext: str) -> str:
pass
def decrypt(self, plaintext: str) -> str:
pass
vc = VigenereCipher()
The method is now a static method of the cipher, nothing outside the classes is referenced. You could opt to name RotateCipher _RotateCipher instead, if you don't want people using it by itself.
Note: I removed the Final, as I ran this on 3.7, but after reading the documentation on Final, I don't think it would affect the solution? Also added an import for string which the question was missing. And finally added an implementation for the abstract methods, alternatively, could have let VigenereCipher inherit from abc.ABC as well.
If your classmethod is not used very often do a lazy evaluation
class A() {
# this does not work: x=A.initMe()
#classmethod
def initMe(cls) {
if not hasattr(cls,"x"):
# your code her
cls.x=# your result
pass
#classmethod
def f1(cls) {
# needs initMe
cls.initMe()
# more code using cls.x
}
}
I am using the python mock framework for testing (http://www.voidspace.org.uk/python/mock/) and I want to mock out a superclass and focus on testing the subclasses' added behavior.
(For those interested I have extended pymongo.collection.Collection and I want to only test my added behavior. I do not want to have to run mongodb as another process for testing purposes.)
For this discussion, A is the superclass and B is the subclass. Furthermore, I define direct and indirect superclass calls as shown below:
class A(object):
def method(self):
...
def another_method(self):
...
class B(A):
def direct_superclass_call(self):
...
A.method(self)
def indirect_superclass_call(self):
...
super(A, self).another_method()
Approach #1
Define a mock class for A called MockA and use mock.patch to substitute it for the test at runtime. This handles direct superclass calls. Then manipulate B.__bases__ to handle indirect superclass calls. (see below)
The issue that arises is that I have to write MockA and in some cases (as in the case for pymongo.collection.Collection) this can involve a lot of work to unravel all of the internal calls to mock out.
Approach #2
The desired approach is to somehow use a mock.Mock() class to handle calls on the the mock just in time, as well as defined return_value or side_effect in place in the test. In this manner, I have to do less work by avoiding the definition of MockA.
The issue that I am having is that I cannot figure out how to alter B.__bases__ so that an instance of mock.Mock() can be put in place as a superclass (I must need to somehow do some direct binding here). Thus far I have determined, that super() examines the MRO and then calls the first class that defines the method in question. I cannot figure out how to get a superclass to handle the check to it and succeed if it comes across a mock class. __getattr__ does not seem to be used in this case. I want super to to think that the method is defined at this point and then use the mock.Mock() functionality as usual.
How does super() discover what attributes are defined within the class in the MRO sequence? And is there a way for me to interject here and to somehow get it to utilize a mock.Mock() on the fly?
import mock
class A(object):
def __init__(self, value):
self.value = value
def get_value_direct(self):
return self.value
def get_value_indirect(self):
return self.value
class B(A):
def __init__(self, value):
A.__init__(self, value)
def get_value_direct(self):
return A.get_value_direct(self)
def get_value_indirect(self):
return super(B, self).get_value_indirect()
# approach 1 - use a defined MockA
class MockA(object):
def __init__(self, value):
pass
def get_value_direct(self):
return 0
def get_value_indirect(self):
return 0
B.__bases__ = (MockA, ) # - mock superclass
with mock.patch('__main__.A', MockA):
b2 = B(7)
print '\nApproach 1'
print 'expected result = 0'
print 'direct =', b2.get_value_direct()
print 'indirect =', b2.get_value_indirect()
B.__bases__ = (A, ) # - original superclass
# approach 2 - use mock module to mock out superclass
# what does XXX need to be below to use mock.Mock()?
#B.__bases__ = (XXX, )
with mock.patch('__main__.A') as mymock:
b3 = B(7)
mymock.get_value_direct.return_value = 0
mymock.get_value_indirect.return_value = 0
print '\nApproach 2'
print 'expected result = 0'
print 'direct =', b3.get_value_direct()
print 'indirect =', b3.get_value_indirect() # FAILS HERE as the old superclass is called
#B.__bases__ = (A, ) # - original superclass
is there a way for me to interject here and to somehow get it to utilize a mock.Mock() on the fly?
There may be better approaches, but you can always write your own super() and inject it into the module that contains the class you're mocking. Have it return whatever it should based on what's calling it.
You can either just define super() in the current namespace (in which case the redefinition only applies to the current module after the definition), or you can import __builtin__ and apply the redefinition to __builtin__.super, in which case it will apply globally in the Python session.
You can capture the original super function (if you need to call it from your implementation) using a default argument:
def super(type, obj=None, super=super):
# inside the function, super refers to the built-in
I played around with mocking out super() as suggested by kindall. Unfortunately, after a great deal of effort it became quite complicated to handle complex inheritance cases.
After some work I realized that super() accesses the __dict__ of classes directly when resolving attributes through the MRO (it does not do a getattr type of call). The solution is to extend a mock.MagicMock() object and wrap it with a class to accomplish this. The wrapped class can then be placed in the __bases__ variable of a subclass.
The wrapped object reflects all defined attributes of the target class to the __dict__ of the wrapping class so that super() calls resolve to the properly patched in attributes within the internal MagicMock().
The following code is the solution that I have found to work thus far. Note that I actually implement this within a context handler. Also, care has to be taken to patch in the proper namespaces if importing from other modules.
This is a simple example illustrating the approach:
from mock import MagicMock
import inspect
class _WrappedMagicMock(MagicMock):
def __init__(self, *args, **kwds):
object.__setattr__(self, '_mockclass_wrapper', None)
super(_WrappedMagicMock, self).__init__(*args, **kwds)
def wrap(self, cls):
# get defined attribtues of spec class that need to be preset
base_attrs = dir(type('Dummy', (object,), {}))
attrs = inspect.getmembers(self._spec_class)
new_attrs = [a[0] for a in attrs if a[0] not in base_attrs]
# pre set mocks for attributes in the target mock class
for name in new_attrs:
setattr(cls, name, getattr(self, name))
# eat up any attempts to initialize the target mock class
setattr(cls, '__init__', lambda *args, **kwds: None)
object.__setattr__(self, '_mockclass_wrapper', cls)
def unwrap(self):
object.__setattr__(self, '_mockclass_wrapper', None)
def __setattr__(self, name, value):
super(_WrappedMagicMock, self).__setattr__(name, value)
# be sure to reflect to changes wrapper class if activated
if self._mockclass_wrapper is not None:
setattr(self._mockclass_wrapper, name, value)
def _get_child_mock(self, **kwds):
# when created children mocks need only be MagicMocks
return MagicMock(**kwds)
class A(object):
x = 1
def __init__(self, value):
self.value = value
def get_value_direct(self):
return self.value
def get_value_indirect(self):
return self.value
class B(A):
def __init__(self, value):
super(B, self).__init__(value)
def f(self):
return 2
def get_value_direct(self):
return A.get_value_direct(self)
def get_value_indirect(self):
return super(B, self).get_value_indirect()
# nominal behavior
b = B(3)
assert b.get_value_direct() == 3
assert b.get_value_indirect() == 3
assert b.f() == 2
assert b.x == 1
# using mock class
MockClass = type('MockClassWrapper', (), {})
mock = _WrappedMagicMock(A)
mock.wrap(MockClass)
# patch the mock in
B.__bases__ = (MockClass, )
A = MockClass
# set values within the mock
mock.x = 0
mock.get_value_direct.return_value = 0
mock.get_value_indirect.return_value = 0
# mocked behavior
b = B(7)
assert b.get_value_direct() == 0
assert b.get_value_indirect() == 0
assert b.f() == 2
assert b.x == 0
I want to implement the decorator pattern in Python, and I wondered if there is a way to write a decorator that just implements the function it wants to modify, without writing boiler-plate for all the functions that are just forwarded to the decorated object. Like so:
class foo(object):
def f1(self):
print "original f1"
def f2(self):
print "original f2"
class foo_decorator(object):
def __init__(self, decoratee):
self._decoratee = decoratee
def f1(self):
print "decorated f1"
self._decoratee.f1()
def f2(self): # I would like to leave that part out
self._decoratee.f2()
I would like to have calls to foo_decorator.f2 forwarded to decoratee.f2 automatically. Is there a way to write a generic method that forwards all unimplemented function-calls to decoratee?
You could use __getattr__:
class foo(object):
def f1(self):
print "original f1"
def f2(self):
print "original f2"
class foo_decorator(object):
def __init__(self, decoratee):
self._decoratee = decoratee
def f1(self):
print "decorated f1"
self._decoratee.f1()
def __getattr__(self, name):
return getattr(self._decoratee, name)
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
As an addendum to Philipp's answer; if you need to not only decorate, but preserve the type of an object, Python allows you to subclass an instance at runtime:
class foo(object):
def f1(self):
print "original f1"
def f2(self):
print "original f2"
class foo_decorator(object):
def __new__(cls, decoratee):
cls = type('decorated',
(foo_decorator, decoratee.__class__),
decoratee.__dict__)
return object.__new__(cls)
def f1(self):
print "decorated f1"
super(foo_decorator, self).f1()
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
print 'isinstance(v, foo) ==', isinstance(v, foo)
This is a bit more involved than strictly necessary for your example, where you know the class being decorated in advance.
This might suffice:
class foo_decorator(foo):
def __init__(self, decoratee):
self.__dict__.update(decoratee.__dict__)
def f1(self):
print "decorated f1"
super(foo_decorator, self).f1()
It's arguably not the best practice, but you can add functionality to instances, as I've done to help transition my code from Django's ORM to SQLAlachemy, as follows:
def _save(self):
session.add(self)
session.commit()
setattr(Base,'save',_save)
The UML diagram in the linked Wikipedia article is wrong and so is your code.
If you follow the "decorator pattern", the decorator class is derived from the base decorated class. (In the UML diagram an inheritance arrow from the WindowDecorator to Window is missing).
with
class foo_decorator(foo):
you don't need to implement undecorated methods.
BTW: In strong typed languages there is one more reason, why the decorator must be derived from the decorated class: Otherwise you wouldnt be able to chain decorators.
In one of my projects, I also needed to do one particular thing, that is that even the underlying object should actually execute the method that was reimplemented in the decorator. It is actually quite easy to do if you know where to target it.
The use case is:
I have an object X with methods A and B.
I create a decorator class Y that overrides A.
If I instantiate Y(X) and call A, it will use the decorated A as expected.
If B calls A, then if I instantiate Y(X) and call B on the decorator, the call from within B then goes to the old A on the original object which was undesirable. I want the old B to call the new A as well.
It is possible to reach this behaviour like this:
import inspect
import six # for handling 2-3 compatibility
class MyBaseDecorator(object):
def __init__(self, decorated):
self.decorated = decorated
def __getattr__(self, attr):
value = getattr(self.decorated, attr)
if inspect.ismethod(value):
function = six.get_method_function(value)
value = function.__get__(self, type(self))
return value
class SomeObject(object):
def a(self):
pass
def b(self):
pass
class MyDecorator(MyBaseDecorator):
def a(self):
pass
decorated = MyDecorator(SomeObject())
This may not work out of the box as I typed everything else apart from the getattr method from top of my head.
The code looks up the requested attribute in the decorated object, and if it is a method (doesn't work for properties now, but the change to support them should not be too difficult), the code then pulls the actual function out of the method and using the descriptor interface invocation it "rebinds" the function as a method, but on the decorator. Then it is returned and most likely executed.
The effect of this is that if b ever calls a on the original object, then when you have the object decorated and there is any method call coming from the decorator, the decorator makes sure that all methods accessed are bound to the decorator instead, therefore looking up things using the decorator and not the original object, therefore the methods specified in the decorator taking precedence.
P.S.: Yes I know it looks pretty much like inheritance, but this done in the sense of composition of multiple objects.
To complement #Alec Thomas reply. I modified his answer to follow the decorator pattern. This way you don't need to know the class you're decorating in advance.
class Decorator(object):
def __new__(cls, decoratee):
cls = type('decorated',
(cls, decoratee.__class__),
decoratee.__dict__)
return object.__new__(cls)
Then, you can use it as:
class SpecificDecorator(Decorator):
def f1(self):
print "decorated f1"
super(foo_decorator, self).f1()
class Decorated(object):
def f1(self):
print "original f1"
d = SpecificDecorator(Decorated())
d.f1()
In Python 3, Philipp's accepted answer raised RuntimeError: maximum recursion depth exceeded.
The way that worked for me:
class Foo(object):
def f1(self):
print("original f1")
def f2(self):
print("original f2")
class FooDecorator(object):
def __init__(self, decoratee):
self._decoratee = decoratee
def f1(self):
print("decorated f1")
return self._decoratee.f1()
def __getattr__(self, name):
if name in ['f1', '_decoratee']:
raise AttributeError()
return getattr(self._decoratee, name)
f = FooDecorator(Foo())
f.f1()
# decorated f1
# original f1
f.f2()
# original f2
The workaround is inspired by Ned Batchelder's blog