I'm trying to create a Proxy class to another class. I want this class to be passed into the proxy in its constructor and then for the proxy to dynamically create all the same methods of this class on itself.
This is what I hvae so far which is not working:
import inspect
from optparse import OptionParser
class MyClass:
def func1(self):
print 'MyClass.func1'
def func2(self):
print 'MyClass.func1'
class ProxyClass:
def __init__(self):
myClass = MyClass()
members = inspect.getmembers(MyClass, predicate=inspect.ismethod)
for member in members:
funcName = member[0]
def fn(self):
print 'ProxyClass.' + funcName
return myClass[funcName]()
self.__dict__[funcName] = fn
proxyClass = ProxyClass()
proxyClass.func1()
proxyClass.func2()
I think it is the line self.__dict__[funcName] = fn that needs to be changed but am not sure what to?
I'm new to Python so if there is a completely different Pythonic way of doing this I would be happy to hear about that too.
I would not explicitly copy the methods of the wrapped class. You can use the magic method __getattr__ to control what happens when you call something on the proxy object, including decorating it as you like; __getattr__ has to return a callable object, so you can make that callable do whatever you need to (in addition to calling the original method).
I have included an example below.
class A:
def foo(self): return 42
def bar(self, n): return n + 5
def baz(self, m, n): return m ** n
class Proxy:
def __init__(self, proxied_object):
self.__proxied = proxied_object
def __getattr__(self, attr):
def wrapped_method(*args, **kwargs):
print("The method {} is executing.".format(attr))
result = getattr(self.__proxied, attr)(*args, **kwargs)
print("The result was {}.".format(result))
return result
return wrapped_method
proxy = Proxy(A())
proxy.foo()
proxy.bar(10)
proxy.baz(2, 10)
Related
I'm trying to add extra decorator for magic method (__get__) in descriptor class.
I'm able to do it when I use #property but not when I use descriptor class.
I check range because my object set registers on the bus and some registers can take only specific range of values:
import functools
def check_range(min, max):
def decorator(f):
#functools.wraps(f)
def wrap(self, value):
if value not in range(min, max+1):
return
return f(self, value)
return wrap
return decorator
This works:
class Foo:
def __init__(self):
self.device.init_smth('my_object')
#property
def my_object(self):
return self.device.get_value('my_object')
#my_object.setter
#check_range(0,1)
def my_object(self, value):
self.device.set_value('my_object', value)
a = Foo()
print(a.my_object)
a.my_object = 1
print(a.my_object)
a.myobject = -1
And in this example everything works the same but check_range is not invoked:
class Register:
def __init__(self, name, device):
self.name = name
device.init_smth(name)
def __get__(self, instance, owner):
return instance.device.get_value(self.name)
#check_range(0,1)
def __set__(self, instance, value):
instance.device.set_value(self.name, value)
class Foo:
def __init__(self):
self.my_object = Register('my_object', self.device)
a = Foo()
print(a.my_object)
a.my_object = 1
print(a.my_object)
a.myobject = -1
I may be wrong, but most probably your descriptor not invoked at all, decorator is not the problem. Descriptors meant to be used like
class Foo2:
my_object = Register('my_object', 'init_value')
— you're defining it like class attribute. And python will execute all machinery with __get__/__set__/__del__ if your class attribute supports it (i.e. it is descriptor).
This is why there is an "instance" argument in descriptor methods — you're defining descriptor as class variable, but i.e. __set__ method will receive actual instance of your class, so you can manage per-instance data, like your device
What I want is something like flask routing register:
class ClassName(object):
def __init__(self):
self.handle_dict = {}
def handle(data):
h = self.handle_dict.get(data)
h()
#handle_route("open")
def open_handle()
"""do something"""
pass
#handle_route("close")
def close_handle()
"""do something"""
pass
def handle_route()
"""How to implement this warpper?"""
I know I could write the a dict in the __init__ function:
self.handle_dict = {"open":self.open_handle, "close":self.colse_handle}
But the decorator way looks more clear, right?
I have tried
def handle_router(self, path):
def warpper(f):
self.handle_map[path] = f
return f
return warpper
but self is not allow in decorator args, #handle_router(self, "path") is invalid.
Effectively, the handle dict should be some sort of class attribute, as it is filled at class definition time and all instances share the same route-handler mapping. However, the class does not exist yet when the decorator is called and evaluated. You could do something like the following:
from functools import partial
class A:
router = {}
def handle(self, data):
m = self.router.get(data)
return m(self)
#partial(router.setdefault, 'open')
def open_handle(self):
return 5
>>> a = A()
>>> a.handle('open')
5
Or be more explicit and extract the routing functionailty to a reuasable class:
from functools import partial
class Router(dict):
__call__ = lambda self, route: partial(self.setdefault, route)
class A:
router = Router()
def handle(self, data):
m = self.router.get(data)
return m(self)
#router('open')
def open_handle(self):
return 5
Instead of decorating the functions, you could just use a consistent naming convention:
class ClassName(object):
def handle(self, type):
getattr(self, '{}_handle'.format(type))()
def open_handle(self):
print('open_handle')
def close_handle(self):
print('close_handle')
ClassName().handle('open')
>>> open_handle
When using classmethod to dynamic change the method in subclass, how to dynamic change signatures of method?
example
import inspect
class ModelBase(object):
#classmethod
def method_one(cls, *args):
raise NotImplementedError
#classmethod
def method_two(cls, *args):
return cls.method_one(*args) + 1
class SubClass(ModelBase):
#staticmethod
def method_one(a, b):
return a + b
test = SubClass()
try:
print(inspect.signature(test.method_two))
except AttributeError:
print(inspect.getargspec(test.method_two).args)
I want test.method_two to get the signatures of test.method_one. How to rewrite parent class ModelBase?
I have read about Preserving signatures of decorated functions. In python3.4 +, functools.wraps helps to preserve signatures of decorated functions. I want to apply it to class method.
when uses functools.wraps, I need to assign decorated method's name. But how to access decorated method outside classmethod in this situation?
from functools import wraps
class ModelBase(object):
#classmethod
def method_one(cls, *args):
raise NotImplementedError
#classmethod
def method_two(cls):
#wraps(cls.method_one)
def fun(*args):
return cls.method_one(*args) + 1
return fun
method_two returns a wrapped function, but I must use it with test.method_two()(*arg). This method is not directly.
If this is only for introspection purpose you could override __getattribute__ on ModelBase and every time method_two is accessed we return a function that has the signature of method_one.
import inspect
def copy_signature(frm, to):
def wrapper(*args, **kwargs):
return to(*args, **kwargs)
wrapper.__signature__ = inspect.signature(frm)
return wrapper
class ModelBase(object):
#classmethod
def method_one(cls, *args):
raise NotImplementedError
#classmethod
def method_two(cls, *args):
return cls.method_one(*args) + 1
def __getattribute__(self, attr):
value = object.__getattribute__(self, attr)
if attr == 'method_two':
value = copy_signature(frm=self.method_one, to=value)
return value
class SubClass(ModelBase):
#staticmethod
def method_one(a, b):
return a + b
class SubClass2(ModelBase):
#staticmethod
def method_one(a, b, c, *arg):
return a + b
Demo:
>>> test1 = SubClass()
>>> print(inspect.signature(test1.method_two))
(a, b)
>>> test2 = SubClass2()
>>> print(inspect.signature(test2.method_two))
(a, b, c, *arg)
I am trying to make a python decorator that adds attributes to methods of a class so that I can access and modify those attributes from within the method itself. The decorator code is
from types import MethodType
class attribute(object):
def __init__(self, **attributes):
self.attributes = attributes
def __call__(self, function):
class override(object):
def __init__(self, function, attributes):
self.__function = function
for att in attributes:
setattr(self, att, attributes[att])
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, owner):
return MethodType(self, instance, owner)
retval = override(function, self.attributes)
return retval
I tried this decorator on the toy example that follows.
class bar(object):
#attribute(a=2)
def foo(self):
print self.foo.a
self.foo.a = 1
Though I am able to access the value of attribute 'a' from within foo(), I can't set it to another value. Indeed, when I call bar().foo(), I get the following AttributeError.
AttributeError: 'instancemethod' object has no attribute 'a'
Why is this? More importantly how can I achieve my goal?
Edit
Just to be more specific, I am trying to find a simple way to implement static variable that are located within class methods. Continuing from the example above, I would like instantiate b = bar(), call both foo() and doo() methods and then access b.foo.a and b.doo.a later on.
class bar(object):
#attribute(a=2)
def foo(self):
self.foo.a = 1
#attribute(a=4)
def doo(self):
self.foo.a = 3
The best way to do this is to not do it at all.
First of all, there is no need for an attribute decorator; you can just assign it yourself:
class bar(object):
def foo(self):
print self.foo.a
self.foo.a = 1
foo.a = 2
However, this still encounters the same errors. You need to do:
self.foo.__dict__['a'] = 1
You can instead use a metaclass...but that gets messy quickly.
On the other hand, there are cleaner alternatives.
You can use defaults:
def foo(self, a):
print a[0]
a[0] = 2
foo.func_defaults = foo.func_defaults[:-1] + ([2],)
Of course, my preferred way is to avoid this altogether and use a callable class ("functor" in C++ words):
class bar(object):
def __init__(self):
self.foo = self.foo_method(self)
class foo_method(object):
def __init__(self, bar):
self.bar = bar
self.a = 2
def __call__(self):
print self.a
self.a = 1
Or just use classic class attributes:
class bar(object):
def __init__(self):
self.a = 1
def foo(self):
print self.a
self.a = 2
If it's that you want to hide a from derived classes, use whatever private attributes are called in Python terminology:
class bar(object):
def __init__(self):
self.__a = 1 # this will be implicitly mangled as __bar__a or similar
def foo(self):
print self.__a
self.__a = 2
EDIT: You want static attributes?
class bar(object):
a = 1
def foo(self):
print self.a
self.a = 2
EDIT 2: If you want static attributes visible to only the current function, you can use PyExt's modify_function:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
It's slightly ugly and hackish. But it works.
My recommendation would be just to use double underscores:
class bar(object):
__a = 1
def foo(self):
print self.__a
self.__a = 2
Although this is visible to the other functions, it's invisible to anything else (actually, it's there, but it's mangled).
FINAL EDIT: Use this:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
foo.a = foo.func_globals['a']
b = bar()
b.foo() # prints 1
b.foo() # prints 2
# external access
b.foo.a[0] = 77
b.foo() # prints 77
While You can accomplish Your goal by replacing self.foo.a = 1 with self.foo.__dict__['a'] = 1 it is generally not recommended.
If you are using Python2 - (and not Python3) - whenever you retrieve a method from an instance, a new instance method object is created which is a wrapper to the original function defined in the class body.
The instance method is a rather transparent proxy to the function - you can retrieve the function's attributes through it, but not set them - that is why setting an item in self.foo.__dict__ works.
Alternatively you can reach the function object itself using: self.foo.im_func - the im_func attribute of instance methods point the underlying function.
Based on other contributors's answers, I came up with the following workaround. First, wrap a dictionnary in a class resolving non-existant attributes to the wrapped dictionnary such as the following code.
class DictWrapper(object):
def __init__(self, d):
self.d = d
def __getattr__(self, key):
return self.d[key]
Credits to Lucas Jones for this code.
Then implement a addstatic decorator with a statics attribute that will store the static attributes.
class addstatic(object):
def __init__(self, **statics):
self.statics = statics
def __call__(self, function):
class override(object):
def __init__(self, function, statics):
self.__function = function
self.statics = DictWrapper(statics)
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, objtype):
from types import MethodType
return MethodType(self, instance)
retval = override(function, self.statics)
return retval
The following code is an example of how the addstatic decorator can be used on methods.
class bar(object):
#attribute(a=2, b=3)
def foo(self):
self.foo.statics.a = 1
self.foo.statics.b = 2
Then, playing with an instance of the bar class yields :
>>> b = bar()
>>> b.foo.statics.a
2
>>> b.foo.statics.b
3
>>> b.foo()
>>> b.foo.statics.a
3
>>> b.foo.statics.b
5
The reason for using this statics dictionnary follows jsbueno's answer which suggest that what I want would require overloading the dot operator of and instance method wrapping the foo function, which I am not sure is possible. Of course, the method's attribute could be set in self.foo.__dict__, but since it not recommended (as suggested by brainovergrow), I came up with this workaround. I am not certain this would be recommended either and I guess it is up for comments.
I'm trying to decorate a class with another class. I also want to inherit from the decorated class, but I get some errors. Here's my code:
class Decorator:
def __init__(self, decorated):
pass
#Decorator
class Foo:
pass
class Goo(Foo):
pass
The error I get when I try to subclass from Foo is this:
Traceback (most recent call last):
File "test.py", line 9, in
class Goo(Foo):
TypeError: __init__() takes exactly 2 positional arguments (4 given)
By adding another init function to Decorator...
def __init__(self, *args):
for arg in args:
print(arg)
... I get the following output:
<class '__main__.Foo'>
Goo
(<__main__.Decorator object at 0x010073B0>,)
{'__module__': '__main__'}
What are those parameters and how should I be using them inside Decorator?
I'll try to answer the "what are those parameters" question. This code:
#Decorator
class Foo:
pass
is equivalent to:
class Foo:
pass
Foo = Decorator(Foo)
This means that Foo ends up being an instance of the Decorator class instead of being a class.
When you try to use this instance as a base of a class (Goo), Python will have to determine a metaclass that will be used to create the new class. In this case it will use Foo.__class__ which equals to Decorator. Then it will call the metaclass with (name, bases, dict) arguments and expect it to return a new class.
This is how you end up with these arguments in Decorator.__init__.
More about this can be found here:
http://www.python.org/download/releases/2.2.3/descrintro/#metaclasses
(particularly the "When a class statement is executed..." part)
Are you trying to add a MixIn to a class after the class has been defined?
If so, you could inject the MixIn this way:
def inject_class(mixin):
def _inject_class(cls):
return type(cls.__name__,(mixin,)+cls.__bases__,dict(cls.__dict__))
return _inject_class
class MixIn(object):
def mix(self):
print('mix')
#inject_class(MixIn)
class Foo(object):
def foo(self):
print('foo')
class Goo(Foo):
def goo(self):
print('goo')
goo=Goo()
goo.mix()
goo.foo()
goo.goo()
prints
mix
foo
goo
If you don't want the generality of inject_class, you could make a specialized class decorator which mixes in Decorator only:
def decorate(cls):
class Decorator(object):
def deco(self):
print('deco')
return type(cls.__name__,(Decorator,)+cls.__bases__,dict(cls.__dict__))
#decorate
class Foo(object):
def foo(self):
print('foo')
the result is the same.
I had the same problem and the following solution works for me:
from functools import update_wrapper
class decoratorBase():
def __new__(cls, logic):
self = object.__new__(cls)
self.__init__(logic)
def new (cls):
#cls is the decorated class type, not the decorator class type itself
self._createInstance(cls)
self._postInstanceCreation()
return self
self._logic.__new__ = new
#return the wrapped class and not a wrapper
return self._logic
def __init__(self, logic):
#logic is the decorated class
self._logic = logic
def _createInstance(self, cls):
self._logicInstance = object.__new__(cls)
self._logicInstance.__init__()
def _postInstanceCreation(self):
pass
class factory(decoratorBase):
def __init__(self, *largs, **kwargs):
super().__init__(*largs, **kwargs)
self.__instance = None
def _createInstance(self, cls):
self._logicInstance = None
self._cls = cls
def _postInstanceCreation(self):
update_wrapper(self, self._cls)
def __call__(self, userData, *largs, **kwargs):
logicInstance = object.__new__(self._cls)
logicInstance.__init__(*largs, **kwargs)
logicInstance._update(userData)
return logicInstance
class singelton(decoratorBase):
def _postInstanceCreation(self):
update_wrapper(self, self._logicInstance)
def __call__(self, userData):
self._logicInstance._update(userData)
return self._logicInstance
class base():
def __init__(self):
self.var = 0
print ("Create new object")
def __call__(self):
self.var += self._updateValue()
def _update(self, userData):
print ("Update object static value with {0}".format(userData))
self.var = userData
#factory
class factoryTestBase(base):
def __call__(self):
super().__call__()
print("I'm a factory, here is the proof: {0}".format(self.var))
def _updateValue(self):
return 1
class factoryTestDerived(factoryTestBase):
def _updateValue(self):
return 5
#singelton
class singeltonTestBase(base):
def __call__(self):
super().__call__()
print("I'm a singelton, here is the proof: {0}".format(self.var))
def _updateValue(self):
return 1
class singeltonTestDerived(singeltonTestBase):
def _updateValue(self):
return 5
The magic in this approach is the overloading of the __new__() method, as well for the decorator itself as for the "wrapper" which is returned by the decorator. I set the word wrapper in quotes, because actually there is no wrapper. Instead the decorated class is alternated by the decorator and returned. Using this scheme, you are able to inherit from a decorated class. The most important thing is the change of the __new__() method of the decorated class, which is made by the following lines:
def new (cls):
self._createInstance(cls)
self._postInstanceCreation()
return self
self._logic.__new__ = new
Using this, you have access to the decorator methods like self._createInstance() during creation of an object from a decorated class. You even have the opportunity to inherit from your decorators (as it is shown in the example).
Now lets run a simple example:
>>> factoryObjCreater = factoryTestBase()
>>> factoryObj1 = factoryObjCreater(userData = 1)
Create new object
Update object static value with 1
>>> factoryObj2 = factoryObjCreater(userData = 1)
Create new object
Update object static value with 1
>>> factoryObj1()
I'm a factory, here is the proof: 2
>>> factoryObj2()
I'm a factory, here is the proof: 2
>>> factoryObjDerivedCreater = factoryTestDerived()
>>> factoryObjDerived1 = factoryObjDerivedCreater(userData = 2)
Create new object
Update object static value with 2
>>> factoryObjDerived2 = factoryObjDerivedCreater(userData = 2)
Create new object
Update object static value with 2
>>> factoryObjDerived1()
I'm a factory, here is the proof: 7
>>> factoryObjDerived2()
I'm a factory, here is the proof: 7
>>> singeltonObjCreater = singeltonTestBase()
Create new object
>>> singeltonObj1 = singeltonObjCreater(userData = 1)
Update object static value with 1
>>> singeltonObj2 = singeltonObjCreater(userData = 1)
Update object static value with 1
>>> singeltonObj1()
I'm a singelton, here is the proof: 2
>>> singeltonObj2()
I'm a singelton, here is the proof: 3
>>> singeltonObjDerivedCreater = singeltonTestDerived()
Create new object
>>> singeltonObjDerived1 = singeltonObjDerivedCreater(userData = 2)
Update object static value with 2
>>> singeltonObjDerived2 = singeltonObjDerivedCreater(userData = 2)
Update object static value with 2
>>> singeltonObjDerived1()
I'm a singelton, here is the proof: 7
>>> singeltonObjDerived2()
I'm a singelton, here is the proof: 12
>>>