Python mixin with dynamic method names - python

Supposing I have the following classes:
class SomeMixin:
def apply(self):
pass
class Foo(SomeMixin):
pass
class Bar(SomeMixin):
pass
How do I implement SomeMixin so that the attached method apply becomes apply_foo in Foo and apply_bar in Bar? The methods in the mixin follows a generic algorithm, but the generated names matter to the framework I'm using.

You wouldn't do that in the mixin, but in the concrete classes themselves. Just define the methods so that they call apply directly.
class Foo(SomeMixin):
def apply_foo(self):
return self.apply()
class Bar(SomeMixin):
def apply_bar(self):
return self.apply()

Related

What is the best to extend functionality of a Library class method

I have a library code that provides class and that class is expected to be a subclass of my frameworks classes.
Now I want to extend one of the functionalities of a library class method, here I can think of 2 approaches:
create a new class with subclass library class then override library class method in a new class
create Mixins override the functionality of the library class method and inherit that as well
Here is a coded way of my above 2 theoretical approaches.
approach 1:
class Library:
def method_one(self):
return {"method_one": "one"}
def method_two(self):
return {"method_two": "two"}
class FrameworkOne(Library):
def method_one(self):
method = super().method_one()
method["label"] = self.__class__.__name__
return method
class FrameworkTwo(Library):
def method_one(self):
method = super().method_one()
method["label"] = self.__class__.__name__
return method
approach 2:
class MixinFramework:
def method_one(self):
method = super().method_one()
method["label"] = self.__class__.__name__
return method
class FrameworkOne(MixinFramework, Library):
pass
class FrameworkTwo(MixinFramework, Library):
pass
another way I can think of is to create another Baseclass which will inherit Library class and override method_one in Base class and inherit Baseclass in all Framework classes instead of Library class
approach one seems to code redundancy issue and approach two seems to me like narrow down
is there any better approach or a decorator way that I can put on to each class where I want to extend the functionality of method_one
Please suggest.

Inherit wrapper from abstract method

I would like to systematically wrap some overriden method of a base class.
I am using ABC for the base class. I tried to wrap the #abstractmethod, putting the annotation before or after, but it doesn’t work. As I understand it, the the whole wrapped method is overriden.
from functools import wraps
from abc import ABC, abstractmethod
def print_before(func):
#wraps(func)
def out(*args, **kwargs):
print('Hello')
return func(*args, **kwargs)
return out
class Base(ABC):
#print_before
#abstractmethod
def test(self):
pass
class Extend(Base):
def test(self):
print('World')
Here is what happens when we test:
Extend().test()
Result:
World
Desired:
Hello
World
I guess I’m not using the right method to get such behavior. What would be a nice pythonic way to run some code before and after an overriden method?
As you noticed, the decorator does not change overridden methods. You could decorate the method every time you create a subclass. You can even do it automatically with the magic method __init_subclass__.
class Base(ABC):
...
def __init_subclass__(cls):
cls.test = print_before(cls.test)
But i would not recommend this approach. It will probably destroy the ABC mechanisms and classes that inherit from Extend are decorated twice if they don't override the method.
Here is a much easier approach. We define a concrete "public" method on Base that calls an abstract "private" method. In the child classes we then have to implement the "private" method.
class Base(ABC):
def test(self):
# do something before
result = self._do_work()
# do something after
return result
#abstractmethod
def _do_work(self):
pass
class Extend(Base):
def _do_work(self):
# your implementation here
# use it like this:
e = Extend()
e.test()
Another advantage is that you can change the behaviour of the "wrapper" in a child class which would be difficult with the decorator.

Annotate subclass's method?

Suppose I have a Mixin class Mixin, and a method a in this class uses another method
b which will be in another Base class. I want to annotate b in class Mixin so that I can take the advantages of inspection.
The real usage is multiple inherition. I create a mixin for tornado.web.RequestHandler, and the subclass could inherit both RequestHandler and Mixin to get some useful functions.
As far as I know, I can annotate b as Callable, but I cannot annotate its signature.
class Base
def b():
# do something
class Mixin:
b: Callable # not enough, losing signature.
#b: RequestHandler.b # not work, still losing signature.
def a():
# call b here.
class subclass(Base, Mixin):
pass
BTW, I'm using Pycharm.

Extending a class hierarchy in Python

I have a class hierarchy in a module that I want to extend.
The module to be extended looks something like this.
Module foo:
class bar(object): pass
class spam(bar): pass
class eggs(bar): pass
Now I want to extend these classes:
class my_bar(foo.bar):
def new_func(): pass
class my_spam(foo.spam): pass
class my_eggs(foo.eggs): pass
Doing so, a new function new_func() in my_bar would not be available in a my_spam instance using
my_spam_instance.new_func()
What is the best ("most pythonic") way to achieve this? I thought of multiple inheritance, like this:
class my_bar(foo.bar): pass
class my_spam(foo.bar, my_bar): pass
class my_eggs(foo.eggs, my_bar): pass
Though I never really used it before and I am not sure this is the best way.
You don't even need to inherit my_bar from bar
pythonic will be adding Mixin, which is actually a base class, but not inherited
class NewFuncMixin():
def new_func(): pass
And add it to new classes
class my_bar(foo.bar, NewFuncMixin): pass
class my_spam(foo.spam, NewFuncMixin): pass
class my_eggs(foo.eggs, NewFuncMixin): pass
What about a mixin class? The pattern is
class My_mixin( object):
def new_func(self): pass
class My_spam( My_mixin, foo.spam): pass
class My_eggs( My_mixin, foo.eggs): pass
mixins should inherit from object, and go on the left of the inheritance list so that the mixin class methods get name priority. Within the mixin you can then wrap any method of the superclass:
class My_mixin( object):
def bar_method( self):
# stuff
bar_result = super( My_mixin, self).bar_method()
# more stuff
return bar_result # or my_result based on bar_result
You can of course completely override the method instead of wrapping it.

Python refer to class from within class

I've become aware of #staticmethod - next question, are you supposed to use the class name to refer to these methods from within the class?
class C:
#staticmethod
def imstatic():
print("i'm static")
#staticmethod
def anotherstatic():
# Is this the proper python way?
C.imstatic()
#staticmethod
def brokenstatic():
# This doesn't work..
self.imstatic()
Yes, as you don't have any other reference to the class from within a static method. You could make these class methods instead, using the classmethod decorator:
class C:
#staticmethod
def imstatic():
print("i'm static")
#classmethod
def anotherstatic(cls):
cls.imstatic()
A class method does have a reference to the class.
If you need to refer to the class within a static method you should probably be using a classmethod instead:
class C:
#staticmethod
def imstatic():
print("i'm static")
#classmethod
def imclass(cls):
cls.imstatic()
In the same way that instance methods are "magically" given a reference to the instance as the first argument, class methods are given a reference to the class. You can call them either from an instance or from the class directly, for example both of the following are valid and have the same behavior:
C().imclass()
C.imclass()
That being said, if you do still want to use a static method your current approach is correct, just refer to the class by name.
If you always want to call the static method of that specific class, yes, you must specify it by name. If you want to support overriding the static methods, what you want is a classmethod instead: it passes the class on which the method is being called as the first parameter, analogous to self on regular instance methods, so you can call the overridden method. In general I'd suggest using classmethods.

Categories

Resources