Suppose that I have two classes:
a class named Swimmer
a class named Person
For my particular application, we can NOT have Swimmer inherit from Person, although we want something like inheritance.
Instead of class inheritance each Swimmer will have an instance of the Person class as a member variable.
class Person:
pass
class Swimmer:
def __init__(self, person):
self._person = person
def __getattr__(self, attrname:str):
try:
attr = getattr(self._person)
return attr
except AttributeError:
raise AttributeError
Perhaps the Person class has the following class methods:
kneel()
crawl()
walk()
lean_over()
lay_down()
The Swimmer class has all of the same methods as the Person class, plus some additional methods:
run()
swim()
dive()
throw_ball()
When it comes to kneeling, crawling, walking, and laying down, a Swimmer is meant to be a transparent wrapper around the Person class.
I want to write something like this:
swimmer_instance = SwimmerClass(person_instance)
I wrote a __getattr__() method.
However, I ran into many headaches with __getattr__().
Consider writing the code self.oops. There is no attribute of the _Swimmer class named oops. We should not look for oops inside of self._person.
Aanytime that I mistyped the name of an attribute of Swimmer, my computer searched for that attribute in the instance of the Person class. Normally, fixing such spelling mistakes is easy. But, with a __getattr__() method, tracking down the problem becomes difficult.
How can I avoid this problem?
Perhaps one option is create a sub-class of the Swimmer class. In the sub-class have have a method, the name of which is a misspelling of __getattr__. However, I am not sure about this idea; please advise me.
class _Swimmer:
def __init__(self, person):
self._person = person
def run(self):
return "I ran"
def swim(self):
return "I swam"
def dive(self):
# SHOULD NOT LOOK FOR `oops` inside of self._person!
self.oops
return "I dove"
def _getattrimp(self, attrname:str):
# MISSPELLING OF `__getattr__`
try:
attr = getattr(self._person)
return attr
except AttributeError:
raise AttributeError
class Swimmer(_Swimmer):
def __getattr__(self, attrname:str):
attr = self._getattrimp(attrname)
return attr
Really, it is important to me that we not look inside of self._person for anything except the following:
Kneel()
Crawl()
Walk()
Lean()
LayDown()
The solution must be more general than just something what works for the Swimmer class and Person class.
How do we write a function which accepts any class as input and pops out a class which has methods of the same name as the input class?
We can get a list of Person attributes by writing person_attributes = dir(Person).
Is it appropriate to dynamically create a sub-class of Swimmer which takes Person as input?
class Person:
def kneel(self, *args, **kwargs):
return "I KNEELED"
def crawl(self, *args, **kwargs):
return "I crawled"
def walk(self, *args, **kwargs):
return "I WALKED"
def lean_over(self, *args, **kwargs):
return "I leaned over"
################################################################
import functools
class TransparentMethod:
def __init__(self, mthd):
self._mthd = mthd
#classmethod
def make_transparent_method(cls, old_method):
new_method = cls(old_method)
new_method = functools.wraps(old_method)
return new_method
def __call__(self, *args, **kwargs):
ret_val = self._mthd(*args, **kwargs)
return ret_val
###############################################################
attributes = dict.fromkeys(dir(Person))
for attr_name in attributes.keys():
old_attr = getattr(Person, attr_name)
new_attr = TransparentMethod.make_transparent_method(old_attr)
name = "_Swimmer"
bases = (object, )
_Swimmer = type(name, bases, attributes)
class Swimmer(_Swimmer):
pass
If I understand your question correctly, you want a function that will combine two classes into one.
The way I did this was to create a blank container class with the 3 parameter type() constructor, then loop over every class passed to the function, using setattr to set new attributes of the container class. I had to blacklist the __class__ and __dict__ attributes because Python doesn't allow one to change these. Note that this function will overwrite previously added methods, such as the __init__() method, so pass the class with the constructor last.
I implemented this in the combineClasses function below. I also provided an example. In the example, I created the a basic Person class and a _Swimmer class. I called combineClasses on these two and stored the resulting class as Swimmer, so it can nicely be called as a wrapper class.
def combineClasses(name, *args):
container = type(name, (object,), {})
reserved = ['__class__', '__dict__']
for arg in args:
for method in dir(arg):
if method not in reserved:
setattr(container, method, getattr(arg, method))
return container
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print(f'Hi, I am {self.name}')
class _Swimmer:
def swim(self):
print('I am swimming')
class _Cashier:
def work(self):
print(f'I am working! My name is {self.name}')
Swimmer = combineClasses('Swimmer', _Swimmer, Person)
bob = Swimmer('Bob')
bob.swim() # => "I am swimming"
bob.sayHi() # => "Hi, I am Bob"
print(bob.name) # => "Bob"
print(type(bob)) # => "<class '__main__.Swimmer'>"
Related
In python, how can I setup a parent class to track methods with a specific decorator for each child seperatly? A quick code snippet of what I am trying to do:
class Parent:
decorated_func_dict = {} #dictionary that stores name->func for decorated functions
def get_func_by_decorator_name(self, name):
#stuff
pass
class Child1(Parent):
#func_name("Bob")
def bob_func(self, *args):
pass
#func_name("Tom")
def func2(self, *args):
pass
class Child2(Parent):
#func_name("Bob")
def func_bob2(self, *args):
pass
foo = Child1()
bar = Child2()
foo.get_func_by_decorator_name("Bob")
#Returns foo.bob_func
bar.get_func_by_decorator_name("Bob")
#Returns bar.func_bob2
Using Python 3.9.
A decorator is not something that makes a function look pretty. It is a callable that ingests an object (not only functions), does some arbitrary operations, and returns a replacement object.
In this case, your decorator should be storing references to function objects in a dictionary somewhere. The problem is that you won't be able to reference the class in which the functions are defined until it is created, which happens well after the decorator is run. You can avoid this by storing the name of the class as well as the name of the function.
The final step here is to properly bind the function objects to methods on the right object. That is something that get_func_by_decorated_name can do for you.
In sum, you can write something like this:
decorated_func_dict = {}
def func_name(cls_name, func_name):
def decorator(func):
decorated_func_dict.setdefault(cls_name, {})[func_name] = func
return func
return decorator
class Parent:
def get_func_by_decorator_name(self, name):
return decorated_func_dict[type(self).__name__][name].__get__(self)
class Child1(Parent):
#func_name("Child1", "Bob")
def bob_func(self, *args):
pass
#func_name("Child1", "Tom")
def func2(self, *args):
pass
class Child2(Parent):
#func_name("Child2", "Bob")
def func_bob2(self, *args):
pass
And indeed you get:
>>> foo.get_func_by_decorator_name("Bob")
<bound method Child1.bob_func of <__main__.Child1 object at 0x000001D58181E070>>
>>> bar.get_func_by_decorator_name("Bob")
<bound method Child2.func_bob2 of <__main__.Child2 object at 0x000001D582041F10>>
Another way to do this is to give your functions a name attribute, which you can then aggregate into a mapping in __init_subclass__ in Parent. This allows you to make an interface a bit closer to what you originally intended:
def func_name(func_name):
def decorator(func):
func.special_name = func_name
return func
return decorator
class Parent:
def __init_subclass__(cls):
cls.decorated_func_dict = {}
for item in cls.__dict__.values():
if hasattr(item, 'special_name'):
cls.decorated_func_dict[item.special_name] = item
del item.special_name # optional
def get_func_by_decorator_name(self, name):
return self.decorated_func_dict[name].__get__(self)
class Child1(Parent):
#func_name("Bob")
def bob_func(self, *args):
pass
#func_name("Tom")
def func2(self, *args):
pass
class Child2(Parent):
#func_name("Bob")
def func_bob2(self, *args):
pass
The results are identical to the first example.
The easiest way would of course be to get access to the child's namespace before the class is created, e.g. with a metaclass.
I'm trying to store specific actions that are defined within a class.
To reduce code duplication, I would like to make use of a mixin class that stores all the actions based on a decorator.
The idea is that it should be straightforward for other people to extend the classes with new actions. I especially want to avoid that these actions are explicitly listed in the source code (this should be handled by the decorator).
This is what I came up with. Unfortunately, in all .actions lists, all the actions from all the classes are listed.
However, I would like to have a solution that only the actions of the specific class are listed.
class ActionMixin:
actions = []
#staticmethod
def action(fun):
ActionMixin.actions.append(fun)
return fun
class Human(ActionMixin):
#ActionMixin.action
def talk(self):
pass
class Dog(ActionMixin):
#ActionMixin.action
def wuff(self):
pass
class Cat(ActionMixin):
#ActionMixin.action
def miau(self):
pass
if __name__ == "__main__":
party = [Human(), Dog()]
possible_actions = [action for memer in party for action in member.actions]
# I would like that possible_actions is now only Human.talk() and Dog.wuff()
# instead it is 2 times all actions
print(len(possible_actions)) # == 6
I would just write my own descriptor here. So:
class Registry:
def __init__(self):
self._registered = []
def __call__(self, func):
self._registered.append(func)
return func
def __get__(self, obj, objtype=None):
return self._registered
class Human:
actions = Registry()
#actions
def talk(self):
pass
class Dog:
actions = Registry()
#actions
def wuff(self):
pass
class Cat:
actions = Registry()
#actions
def miau(self):
pass
So, instead of inheriting from a mixin, just initialize the descriptor object. Then that object itself can be used as the decorator (the __call__ method!).
Note, the decorator would be whatever name you assigned it, and it would be the name of the attribute where the actions are stored.
In the REPL:
In [11]: party = [Human(), Dog()]
In [12]: [action for member in party for action in member.actions]
Out[12]: [<function __main__.Human.talk(self)>, <function __main__.Dog.wuff(self)>]
EDIT:
You would have to change the implementation if you want this to live in a base class. Basically, use a dict to keep track of the registries, unfortunately, we have to rely on the brittle __qualname__ to get the class in __call__:
class ActionsRegistry:
def __init__(self):
self._registry = {}
def __call__(self, func):
klass_name, func_name = func.__qualname__.rsplit('.', 1)
if klass_name not in self._registry:
self._registry[klass_name] = []
self._registry[klass_name].append(func)
return func
def __get__(self, obj, objtype=None):
if obj is None:
return self
return self._registry[objtype.__qualname__]
class Base:
actions = ActionsRegistry()
class Human(Base):
#Base.actions
def talk(self):
pass
class Dog(Base):
#Base.actions
def wuff(self):
pass
class Cat(Base):
#Base.actions
def miau(self):
pass
I have the code something like:
class ClassPrintable:
#classmethod
def print_class(cls):
print(cls)
I would like to be able to derive classes from this, and furthermore call the class methods inline from the class body, eg.
class MyClass(ClassPrintable):
print_class()
Unfortunately this doesn't work, however this does:
class MyClass(ClassPrintable):
ClassPrintable.print_class()
Unfortunately, of course, it prints the class for ClassPrintable rather than MyClass
The obvious solution, doesn't work, eg.
class MyClass(ClassPrintable):
MyClass.print_class()
Python complains it can't find MyClass! with a NameError: name 'MyClass' is not defined
How can I access MyClass's class method from within the body of its definition? I would prefer not to use dynanic metaprogramming but I will if I have to.
You cannot invoke anything on the class before it exists which is only after the class definition (note that method bodies aren't evaluated at class definition time). In Python >= 3.6, you can do the following, using the __init_subclass__ hook:
class ClassPrintable:
#classmethod
def print_class(cls):
print(cls)
#classmethod
def __init_subclass__(cls):
cls.print_class()
class MyClass(ClassPrintable):
pass
Alright I figured it out with small amount of metaprogramming. Whoever thought of __init_subclass__ is a genius. If anyone can see anything drastically wrong with this let me know.
import copy
class Model:
def __init__(self, name, default):
self.model_name = name
self.model_default = default
self.observers = []
class Models():
model_dictionary = {}
def __init_subclass__(cls, models=[]):
setattr(cls, "model_dictionary", {})
for model in models:
cls.model_dictionary[model[0]] = Model(model[0], model[1])
for c in cls.__bases__:
cls.add_base_models(c)
#classmethod
def add_base_models(cls, base):
if hasattr(base, "model_dictionary"):
for model in base.model_dictionary.values():
cls.model_dictionary[model.model_name] = copy.copy(base.model_dictionary[model.model_name])
for c in base.__bases__:
cls.add_base_models(c)
#classmethod
def listen(cls, name, closure):
cls.model_dictionary[name].observers.append(closure)
def __init__(self):
for model in self.model_dictionary.values():
super().__setattr__(model.model_name, model.model_default)
def __setattr__(self, name, value):
if name in self.__class__.model_dictionary.keys():
orig_value = getattr(self, name)
if value != orig_value:
for observer in self.model_dictionary[name].observers:
observer(self, value)
super().__setattr__(name, value)
else:
super().__setattr__(name, value)
Sample use of the code:
class Mouse(Models, models=[("x", 100), ("y", 200), ("visible", True)]):
pass
class SpecialMouse(Mouse, models=[("anger_level", "hostile")]):
pass
mouse = SpecialMouse()
mouse.listen("anger_level", lambda mouse, value : print(value))
mouse.anger_level = "cold!"
mouse.anger_level = "warm"
mouse.anger_level = "warm"
mouse.anger_level = "furious"
Prints out:
cold!
warm
furious
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))
I have python class trees, each made up of an abstract base class and many deriving concrete classes. I want all concrete classes to be accessible through a base-class method, and I do not want to specify anything during child-class creation.
This is what my imagined solution looks like:
class BaseClassA(object):
# <some magic code around here>
#classmethod
def getConcreteClasses(cls):
# <some magic related code here>
class ConcreteClassA1(BaseClassA):
# no magic-related code here
class ConcreteClassA2(BaseClassA):
# no magic-related code here
As much as possible, I'd prefer to write the "magic" once as a sort of design pattern. I want to be able to apply it to different class trees in different scenarios (i.e. add a similar tree with "BaseClassB" and its concrete classes).
Thanks Internet!
you can use meta classes for that:
class AutoRegister(type):
def __new__(mcs, name, bases, classdict):
new_cls = type.__new__(mcs, name, bases, classdict)
#print mcs, name, bases, classdict
for b in bases:
if hasattr(b, 'register_subclass'):
b.register_subclass(new_cls)
return new_cls
class AbstractClassA(object):
__metaclass__ = AutoRegister
_subclasses = []
#classmethod
def register_subclass(klass, cls):
klass._subclasses.append(cls)
#classmethod
def get_concrete_classes(klass):
return klass._subclasses
class ConcreteClassA1(AbstractClassA):
pass
class ConcreteClassA2(AbstractClassA):
pass
class ConcreteClassA3(ConcreteClassA2):
pass
print AbstractClassA.get_concrete_classes()
I'm personnaly very wary of this kind of magic. Don't put too much of this in your code.
Here is a simple solution using modern python's (3.6+) __init__subclass__ defined in PEP 487. It allows you to avoid using a meta-class.
class BaseClassA(object):
_subclasses = []
#classmethod
def get_concrete_classes(cls):
return list(cls._subclasses)
def __init_subclass__(cls):
BaseClassA._subclasses.append(cls)
class ConcreteClassA1(BaseClassA):
pass # no magic-related code here
class ConcreteClassA2(BaseClassA):
pass # no magic-related code here
print(BaseClassA.get_concrete_classes())
You should know that part of the answer you're looking for is built-in. New-style classes automatically keep a weak reference to all of their child classes which can be accessed with the __subclasses__ method:
#classmethod
def getConcreteClasses(cls):
return cls.__subclasses__()
This won't return sub-sub-classes. If you need those, you can create a recursive generator to get them all:
#classmethod
def getConcreteClasses(cls):
for c in cls.__subclasses__():
yield c
for c2 in c.getConcreteClasses():
yield c2
Another way to do this, with a decorator, if your subclasses are either not defining __init__ or are calling their parent's __init__:
def lister(cls):
cls.classes = list()
cls._init = cls.__init__
def init(self, *args, **kwargs):
cls = self.__class__
if cls not in cls.classes:
cls.classes.append(cls)
cls._init(self, *args, **kwargs)
cls.__init__ = init
#classmethod
def getclasses(cls):
return cls.classes
cls.getclasses = getclasses
return cls
#lister
class A(object): pass
class B(A): pass
class C(A):
def __init__(self):
super(C, self).__init__()
b = B()
c = C()
c2 = C()
print 'Classes:', c.getclasses()
It will work whether or not the base class defines __init__.