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.
Related
I have a class like:
class MyClass:
Foo = 1
Bar = 2
Whenever MyClass.Foo or MyClass.Bar is invoked, I need a custom method to be invoked before the value is returned. Is it possible in Python? I know it is possible if I create an instance of the class and I can define my own __getattr__ method. But my scnenario involves using this class as such without creating any instance of it.
Also I need a custom __str__ method to be invoked when str(MyClass.Foo) is invoked. Does Python provide such an option?
__getattr__() and __str__() for an object are found on its class, so if you want to customize those things for a class, you need the class-of-a-class. A metaclass.
class FooType(type):
def _foo_func(cls):
return 'foo!'
def _bar_func(cls):
return 'bar!'
def __getattr__(cls, key):
if key == 'Foo':
return cls._foo_func()
elif key == 'Bar':
return cls._bar_func()
raise AttributeError(key)
def __str__(cls):
return 'custom str for %s' % (cls.__name__,)
class MyClass:
__metaclass__ = FooType
# # in python 3:
# class MyClass(metaclass=FooType):
# pass
print(MyClass.Foo)
print(MyClass.Bar)
print(str(MyClass))
printing:
foo!
bar!
custom str for MyClass
And no, an object can't intercept a request for a stringifying one of its attributes. The object returned for the attribute must define its own __str__() behavior.
(I know this is an old question, but since all the other answers use a metaclass...)
You can use the following simple classproperty descriptor:
class classproperty(object):
""" #classmethod+#property """
def __init__(self, f):
self.f = classmethod(f)
def __get__(self, *a):
return self.f.__get__(*a)()
Use it like:
class MyClass(object):
#classproperty
def Foo(cls):
do_something()
return 1
#classproperty
def Bar(cls):
do_something_else()
return 2
For the first, you'll need to create a metaclass, and define __getattr__() on that.
class MyMetaclass(type):
def __getattr__(self, name):
return '%s result' % name
class MyClass(object):
__metaclass__ = MyMetaclass
print MyClass.Foo
For the second, no. Calling str(MyClass.Foo) invokes MyClass.Foo.__str__(), so you'll need to return an appropriate type for MyClass.Foo.
Surprised no one pointed this one out:
class FooType(type):
#property
def Foo(cls):
return "foo!"
#property
def Bar(cls):
return "bar!"
class MyClass(metaclass=FooType):
pass
Works:
>>> MyClass.Foo
'foo!'
>>> MyClass.Bar
'bar!'
(for Python 2.x, change definition of MyClass to:
class MyClass(object):
__metaclass__ = FooType
)
What the other answers say about str holds true for this solution: It must be implemented on the type actually returned.
Depending on the case I use this pattern
class _TheRealClass:
def __getattr__(self, attr):
pass
LooksLikeAClass = _TheRealClass()
Then you import and use it.
from foo import LooksLikeAClass
LooksLikeAClass.some_attribute
This avoid use of metaclass, and handle some use cases.
I have a boiler platey class that delegates some actions to a reference class. It looks like this:
class MyClass():
def __init__(self, someClass):
self.refClass = someClass
def action1(self):
self.refClass.action1()
def action2(self):
self.refClass.action2()
def action3(self):
self.refClass.action3()
This is the refClass:
class RefClass():
def __init__(self):
self.myClass = MyClass(self)
def action1(self):
#Stuff to execute action1
def action2(self):
#Stuff to execute action2
def action3(self):
#Stuff to execute action3
I'd like to use Python Metaprogramming to make this more elegant and readable, but I'm not sure how.
I've heard of setattr and getattr, and I think I could do something like
class MyClass():
def __init__(self, someClass):
self.refClass = someClass
for action in ['action1', 'action2', 'action3']:
def _delegate(self):
getattr(self.refClass, action)()
And then I know I need to do this from somewhere, I guess:
MyClass.setattr(action, delegate)
I just can't totally grasp this concept. I understand the basics about not repeating code, and generating the methods with a for loop with functional programming, but then I don't know how to call this methods from elsewhere. Heeeelp!
Python already includes support for generalized delegation to a contained class. Just change the definition of MyClass to:
class MyClass:
def __init__(self, someClass):
self.refClass = someClass # Note: You call this someClass, but it's actually some object, not some class in your example
def __getattr__(self, name):
return getattr(self.refClass, name)
When defined, __getattr__ is called on the instance with the name of the accessed attribute any time an attribute is not found on the instance itself. You then delegate to the contained object by calling getattr to look up the attribute on the contained object and return it. This costs a little each time to do the dynamic lookup, so if you want to avoid it, you can lazily cache attributes when they're first requested by __getattr__, so subsequent access is direct:
def __getattr__(self, name):
attr = getattr(self.refClass, name)
setattr(self, name, attr)
return attr
Personally, for delegating things I usually do something like that:
def delegate(prop_name, meth_name):
def proxy(self, *args, **kwargs):
prop = getattr(self, prop_name)
meth = getattr(prop, meth_name)
return meth(*args, **kwargs)
return proxy
class MyClass(object):
def __init__(self, someClass):
self.refClass = someClass
action1 = delegate('refClass', 'action1')
action2 = delegate('refClass', 'action2')
This will create all delegate methods you need :)
For some explanations, the delegate function here just create a "proxy" function which will act as a class method (see the self argument?) and will pass all arguments given to it to the referenced object's method with the args and kwargs arguments (see *args and **kwargs? for more informations about these arguments)
You can create this with a list too, but I prefer the first because it's more explicit for me :)
class MyClass(object):
delegated_methods = ['action1', 'action2']
def __init__(self, someClass):
self.refClass = someClass
for meth_name in self.delegated_methods:
setattr(self, meth_name, delegate('refClass', meth_name))
class A(object):
#classmethod
def print(cls):
print 'A'
def __print(self):
print 'B'
def __init__(self):
self.print = self.__print
a = A()
a.print()
A.print()
I think it's too ugly, is there any other method to implement the same features? do not say combinemethod, because it creates an object every time.
The simplest solution is to create a descriptor decorator like classmethod but that also passes the instance to the method:
from functools import partial
class descriptormethod(object):
def __init__(self, fn):
self.fn = fn
def __get__(self, instance, owner):
return partial(self.fn, instance, owner)
class A(object):
#descriptormethod
def print_(self, cls):
print 'A' if self is None else 'B'
Don't worry about the overhead of the descriptor or partial objects; it's no different from what happens when you call an instance or class method normally.
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
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.