Redirect built-in functions to wrapped class - python

I want to make a wrapper class that behaves in exactly the same way as the wrapped object (with a few specific exceptions). The problem I'm having at the moment is with built-in functions. How could I redirect built-in functions to the wrapped object?
class Wrapper:
def __init__(self, wrapped):
object.__setattr__(self, '_wrapped', wrapped)
def __getattr__(self, name):
return getattr(object.__getattribute__(self, '_wrapped'), name)
class Foo:
def __init__(self, val):
self.val = val
def __abs__(self):
return abs(self.val)
foo = Wrapper(Foo(-1))
print(foo.val) # Okay
print(abs(foo)) # TypeError: bad operand type for abs(): 'Wrapper'

You can dynamically create a new class that is subclass of both Wrapper and Foo, so you'll have all the properties needed:
class Wrapper:
def __new__(self, wrapped):
cls = type(wrapped)
new_type = type(cls.__name__ + '_wrapped', (Wrapper, cls), {})
return object.__new__(new_type)
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, name):
return getattr(self._wrapped, name)
So now you can do:
>>> foo = Wrapper(Foo(-1))
>>> abs(foo)
1
>>> type(foo)
<class '__main__.Foo_wrapped'>
PS:
You don't need object.__getattr__ (or __setattr__) in the __init__ and __getattr__ functions to get and set this attribute.
You may want to cache this operation to avoid creating a new class at every new object.

Related

Accessing static fields from the decorated class

Full code example:
def decorator(class_):
class Wrapper:
def __init__(self, *args, **kwargs):
self.instance = class_(*args, **kwargs)
#classmethod
def __getattr__(cls, attr):
return getattr(class_, attr)
return Wrapper
#decorator
class ClassTest:
static_var = "some value"
class TestSomething:
def test_decorator(self):
print(ClassTest.static_var)
assert True
When trying to execute test, getting error:
test/test_Framework.py F
test/test_Framework.py:37 (TestSomething.test_decorator)
self = <test_Framework.TestSomething object at 0x10ce3ceb8>
def test_decorator(self):
> print(ClassTest.static_var)
E AttributeError: type object 'Wrapper' has no attribute 'static_var'
Is it possible to access static fields from the decorated class?
While the answer from #martineau probably better addresses the specific issue you are trying to solve, the more general approach might be to use create a metaclass in order to redefine the instance method __getattr__ on a type instance (and classes are instances of type).
def decorator(class_):
class WrapperMeta(type):
def __getattr__(self, attr):
return getattr(class_, attr)
class Wrapper(metaclass=WrapperMeta):
def __init__(self, *args, **kwargs):
self.instance = class_(*args, **kwargs)
return Wrapper
This allows the attribute look-up on the class itself to be passed through WrapperMeta.__getattr__.
You can get it to work by making the decorator create a class derived from the one being decorated.
Here's what I mean:
def decorator(class_):
class Wrapper(class_):
def __init__(self, *args, **kwargs):
self.instance = super().__init__(*args, **kwargs)
return Wrapper
#decorator
class ClassTest:
static_var = "some value"
print(ClassTest.static_var) # -> some value

Use class method not instance method with the same name

I have the following snippet:
class Meta(type):
def __getattr__(self, name):
pass
class Klass(object):
__metaclass__ = Meta
def get(self, arg):
pass
Now, if I do:
kls = Klass()
kls.get('arg')
everything works as expected (the instance method get is called).
But if I do:
Klass.get('arg')
again the instance method is found and an exception is given, since it is treated as an unbound method.
How can I make a call to Klass.get('arg') go through the __getattr__ defined in the metaclass? I need this because I want to proxy all methods called on a class to another object (this would be done in __getattr__).
You'll have to look up the method on the type and pass in the first (self) argument manually:
type(Klass).get(Klass, 'arg')
This problem is the very reason that special method names are looked up using this path; custom classes would not be hashable or representable themselves if Python didn't do this.
You could make use of that fact; rather than use a get() method, use __getitem__, overloading [..] indexing syntax, and have Python do the type(ob).methodname(ob, *args) dance for you:
class Meta(type):
def __getitem__(self, arg):
pass
class Klass(object):
__metaclass__ = Meta
def __getitem__(self, arg):
pass
and then Klass()['arg'] and Klass['arg'] work as expected.
However, if you have to have Klass.get() behave differently (and the lookup for this to be intercepted by Meta.__getattribute__) you have to explicitly handle this in your Klass.get method; it'll be called with one argument less if called on the class, you could make use of that and return a call on the class:
_sentinel = object()
class Klass(object):
__metaclass__ = Meta
def get(self, arg=_sentinel):
if arg=_sentinel:
if isinstance(self, Klass):
raise TypeError("get() missing 1 required positional argument: 'arg'")
return type(Klass).get(Klass, self)
# handle the instance case ...
You could also handle this in a descriptor that mimics method objects:
class class_and_instance_method(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, cls=None):
if instance is None:
# return the metaclass method, bound to the class
type_ = type(cls)
return getattr(type_, self.func.__name__).__get__(cls, type_)
return self.func.__get__(instance, cls)
and use this as a decorator:
class Klass(object):
__metaclass__ = Meta
#class_and_instance_method
def get(self, arg):
pass
and it'll redirect look-ups to the metaclass if there is no instance to bind to:
>>> class Meta(type):
... def __getattr__(self, name):
... print 'Meta.{} look-up'.format(name)
... return lambda arg: arg
...
>>> class Klass(object):
... __metaclass__ = Meta
... #class_and_instance_method
... def get(self, arg):
... print 'Klass().get() called'
... return 'You requested {}'.format(arg)
...
>>> Klass().get('foo')
Klass().get() called
'You requested foo'
>>> Klass.get('foo')
Meta.get look-up
'foo'
Applying the decorator can be done in the metaclass:
class Meta(type):
def __new__(mcls, name, bases, body):
for name, value in body.iteritems():
if name in proxied_methods and callable(value):
body[name] = class_and_instance_method(value)
return super(Meta, mcls).__new__(mcls, name, bases, body)
and you can then add methods to classes using this metaclass without having to worry about delegation:
>>> proxied_methods = ('get',)
>>> class Meta(type):
... def __new__(mcls, name, bases, body):
... for name, value in body.iteritems():
... if name in proxied_methods and callable(value):
... body[name] = class_and_instance_method(value)
... return super(Meta, mcls).__new__(mcls, name, bases, body)
... def __getattr__(self, name):
... print 'Meta.{} look-up'.format(name)
... return lambda arg: arg
...
>>> class Klass(object):
... __metaclass__ = Meta
... def get(self, arg):
... print 'Klass().get() called'
... return 'You requested {}'.format(arg)
...
>>> Klass.get('foo')
Meta.get look-up
'foo'
>>> Klass().get('foo')
Klass().get() called
'You requested foo'

Delegating #classmethods in python

I need a delegated class to delegate a #classmethod. Here's what I've tried:
class Foo(object):
def __init__(self, a):
self.a = a
#classmethod
def from_a(cls, a):
return cls(a)
class Bar(object):
def __init__(self, foo):
elf._foo = foo
def __getattribute__(self, name):
return getattr(self._foo, name)
But, of course this doesn't define how to look up attributes of Foo (not of an instance of Foo), so Bar.from_a(5) will raise an AttributeError. While it is of course possible to do this explicitly by defining a from_a method on Bar or to do this at instantiation by calling Bar(Foo.from_a(5)), I would rather do this implicitly. Ideas?
I started working on what I thought would be a simple approach for this using a metaclass, but it is actually fairly complex. What you should probably be doing here is having Bar inherit from Foo, but I'll show you what I came up with all the same:
import types
import functools
def make_delegating_type(delegatee):
class DelegatingType(type):
def __getattr__(self, name):
obj = getattr(delegatee, name)
if isinstance(obj, (types.FunctionType, types.MethodType)):
#functools.wraps(obj)
def wrapper(*args, **kwargs):
result = obj(*args, **kwargs)
if isinstance(result, delegatee):
return self(result)
return result
return wrapper
return obj
return DelegatingType
class Foo(object):
def __init__(self, a): self.a = a
#classmethod
def from_a(cls, a): return cls(a)
class Bar(object):
__metaclass__ = make_delegating_type(Foo)
def __init__(self, foo): self._foo = foo
def __getattr__(self, name): return getattr(self._foo, name)
Note that in 3.x you would use class Bar(object, metaclass=make_delegating_type(Foo) instead of the __metaclass__ = make_delegating_type(Foo) line at the top of the Bar class body.
Here is how this works. Your current version currently delegates attribute lookups on instances of Bar to an instance of Foo, this uses a metaclass so that attributes lookups on the class Bar are delegated to the class Foo as well. Unfortunately it is not as simple as just using a __getattr__ definition that returns getattr(delegatee, name), because if the attribute your a looking up is a factory function as in your example you need a version of that factory function that will return an instance of your delegating type. So for example Bar.from_a(5) should be the same as Bar(Foo.from_a(5)), and with the naive approach you would just get Foo.from_a(5). That is why there is all the logic detecting if the attribute is a function or method, and creating a wrapper that checks the return type of that function/method.
To reiterate, I do not recommend that you use this code! It is much more complicated then just defining from_a on Bar or having Bar inherit from Foo. But hopefully it will be a learning experience for you, as it was for me.

Automatically decorate superclass functions in subclass?

I have a subclass that adds graphics capabilities to a superclass that implements the algorithms. So, in addition to a few extra initialization functions, this subclass will only need to refresh the graphics after the execution of each algorithm-computing function in the superclass.
Classes:
class graph(algorithms):
... #initialization and refresh decorators
#refreshgraph
def algorithm1(self, *args, **kwargs):
return algorithms.algorithm1(self, *args, **kwargs)
#refreshgraph
def algorithm2(self, *args, **kwargs):
return algorithms.algorithm2(self, *args, **kwargs)
... #and so on
Is there an pythonic way to automatically decorate all the non-private methods defined in the superclass, such that if I add a new algorithm there I don't need to explicitly mention it in my subclass? I would also like to be able to explicitly exclude some of the superclass' methods.
The subclass always gets all the methods from the parent class(es) by default. If you wish to make emulate the behavior other languages use for privacy (eg the 'private' or 'protected' modifiers in C#) you have two options:
1) Python convention (and it's just a convention) is that methods with a single leading underscore in their names are not designed for access from outside the defining class.
2) Names with a double leading underscore are mangled in the bytecode so they aren't visible to other code under their own names. ParentClass.__private is visible inside ParentClass, but can only be accessed from outside ParentClass as ParentClass._ParentClass__private. (Great explanations here). Nothing in Python is truly private ;)
To override an inherited method just define the same name in a derived class. To call the parent class method inside the derived class you can do it as you did in your example, or using super:
def algorithm2(self, *args, **kwargs):
super(graph, self).algorithm2(self, *args, **kwargs)
# do other derived stuff here....
self.refresh()
This is ugly, but I think it does what you want, but without inheritance:
class DoAfter(object):
def __init__(self, obj, func):
self.obj = obj
self.func = func
def __getattribute__(self, attr, *a, **kw):
obj = object.__getattribute__(self, 'obj')
if attr in dir(obj):
x = getattr(obj, attr)
if callable(x):
def b(*a, **kw):
retval = x(*a, **kw)
self.func()
return retval
return b
else:
return x
else:
return object.__getattribute__(self, attr)
Use it like this:
>>> class A(object):
... def __init__(self):
... self.a = 1
...
... def boo(self, c):
... self.a += c
... return self.a
>>> def do_something():
... print 'a'
>>> a = A()
>>> print a.boo(1)
2
>>> print a.boo(2)
4
>>> b = DoAfter(a, do_something)
>>> print b.boo(1)
a
5
>>> print b.boo(2)
a
7
A increments a counter each time A.boo is called. DoAfter wraps A, so that any method in the instance a can be called as if it were a member of b. Note that every method is wrapped this way, so do_something() is called whenever a method is accessed.
This is barely tested, not recommended, and probably a bad idea. But, I think it does what you asked for.
EDIT: to do this with inheritance:
class graph(algorithms):
def refreshgraph(self):
print 'refreshgraph'
def __getattribute__(self, attr):
if attr in dir(algorithms):
x = algorithms.__getattribute__(self, attr)
if callable(x):
def wrapped(*a, **kw):
retval = x(*a, **kw)
self.refreshgraph()
return retval
return wrapped
else:
return x
else:
return object.__getattribute__(self, attr)

dynamically adding callable to class as instance "method"

I implemented a metaclass that tears down the class attributes for classes created with it and builds methods from the data from those arguments, then attaches those dynamically created methods directly to the class object (the class in question allows for easy definition of web form objects for use in a web testing framework). It has been working just fine, but now I have a need to add a more complex type of method, which, to try to keep things clean, I implemented as a callable class. Unfortunately, when I try to call the callable class on an instance, it is treated as a class attribute instead of an instance method, and when called, only receives its own self. I can see why this happens, but I was hoping someone might have a better solution than the ones I've come up with. Simplified illustration of the problem:
class Foo(object):
def __init__(self, name, val):
self.name = name
self.val = val
self.__name__ = name + '_foo'
self.name = name
# This doesn't work as I'd wish
def __call__(self, instance):
return self.name + str(self.val + instance.val)
def get_methods(name, foo_val):
foo = Foo(name, foo_val)
def bar(self):
return name + str(self.val + 2)
bar.__name__ = name + '_bar'
return foo, bar
class Baz(object):
def __init__(self, val):
self.val = val
for method in get_methods('biff', 1):
setattr(Baz, method.__name__, method)
baz = Baz(10)
# baz.val == 10
# baz.biff_foo() == 'biff11'
# baz.biff_bar() == 'biff12'
I've thought of:
Using a descriptor, but that seems way more complex than is necessary here
Using a closure inside of a factory for foo, but nested closures are ugly and messy replacements for objects most of the time, imo
Wrapping the Foo instance in a method that passes its self down to the Foo instance as instance, basically a decorator, that is what I actually add to Baz, but that seems superfluous and basically just a more complicated way of doing the same thing as (2)
Is there a better way then any of these to try to accomplish what I want, or should I just bite the bullet and use some closure factory type pattern?
One way to do this is to attach the callable objects to the class as unbound methods. The method constructor will work with arbitrary callables (i.e. instances of classes with a __call__() method)—not just functions.
from types import MethodType
class Foo(object):
def __init__(self, name, val):
self.name = name
self.val = val
self.__name__ = name + '_foo'
self.name = name
def __call__(self, instance):
return self.name + str(self.val + instance.val)
class Baz(object):
def __init__(self, val):
self.val = val
Baz.biff = MethodType(Foo("biff", 42), None, Baz)
b = Baz(13)
print b.biff()
>>> biff55
In Python 3, there's no such thing as an unbound instance method (classes just have regular functions attached) so you might instead make your Foo class a descriptor that returns a bound instance method by giving it a __get__() method. (Actually, that approach will work in Python 2.x as well, but the above will perform a little better.)
from types import MethodType
class Foo(object):
def __init__(self, name, val):
self.name = name
self.val = val
self.__name__ = name + '_foo'
self.name = name
def __call__(self, instance):
return self.name + str(self.val + instance.val)
def __get__(self, instance, owner):
return MethodType(self, instance) if instance else self
# Python 2: MethodType(self, instance, owner)
class Baz(object):
def __init__(self, val):
self.val = val
Baz.biff = Foo("biff", 42)
b = Baz(13)
print b.biff()
>>> biff55
The trouble you're running into is that your object is not being bound as a method of the Baz class you're putting it in. This is because it is not a descriptor, which regular functions are!
You can fix this by adding a simple __get__ method to your Foo class that makes it into a method when it's accessed as a descriptor:
import types
class Foo(object):
# your other stuff here
def __get__(self, obj, objtype=None):
if obj is None:
return self # unbound
else:
return types.MethodType(self, obj) # bound to obj

Categories