Log common method among classes in python - python

I am importing several classes from a library with a common method, like
class BarClass1:
def __init__(self):
pass
def bar(self, x):
return x + 1
class BarClass2:
def __init__(self):
pass
def bar(self, x):
return x + 2
class BarClass3:
def __init__(self):
pass
def bar(self, x):
return x + 3
I want to add logging to the bar method of each class, and for that purpose I create children for these classes in the following way:
def log_something(x):
print(f'input is {x}')
class DerivedBarClass1(BarClass1):
def __init__(self):
super().__init__()
def bar(self, x):
log_something(x)
return super().bar()
class DerivedBarClass2(BarClass2):
def __init__(self):
super().__init__()
def bar(self, x):
log_something(x)
return super().bar()
class DerivedBarClass3(BarClass3):
def __init__(self):
super().__init__()
def bar(self, x):
log_something(x)
return super().bar()
I feel I am doing a lot of code repetition, is there a simpler way of doing this? My main constraint is not being able to modify the code in BarClass1, BarClass2 or BarClass3.

If you can't modify the code, you can always monkey-patch the classes...
import functools
def add_logging_single_arg(f): # maybe a better name...
#functools.wraps(f)
def wrapper(self, x):
log_something(x)
return f(x)
return wrapper
for klass in [BarClass1, BarClass2, BarClass3]:
klass.bar = add_logging_single_arg(bar)

Related

Using a variable from one class to another one in python

I want to use a variable from class A for some computation in class B. I,m not sure that I use the self.out from the class A in class B appropriately?
Class A:
class A(nn.Module):
def __init__(self):
super(A, self).__init__()
self.out = func()
Class B:
class B(nn.Module):
def __init__(self):
super(A, self).__init__()
self.result = function_1() + A.self.out
Maybe this is what you need. I made a small example of what I understood.
These "prints" were placed to improve the understanding that Class "C" can fetch any function or variable from the other parent classes.
class A():
def __init__(self):
variable = None
def test(self, number):
return f'another class {number}'
class B():
def __init__(self):
self.data = None
self.out = self.print_data(5)
def print_data(self, number):
return number
def print_elem(self):
return self.data
class C(A, B):
def __init__(self):
super().__init__()
c = C()
print(c.print_data(8))
print(c.out)
c.data = 100
print(c.print_elem())
print(c.test(3))

Implementing a generic and dynamic facade for python classes

I wanted to implement a sort of facade pattern in python. However because I need to do the same for all methods, I'd like to do it in a generic way. Let me use an example:
class MyObject:
def __init__(self, *args, **kwargs):
# do something with args/kwargs
def method1(self, x):
# do something
def method2(self, x, a):
# do something
def method3(self, x, a, b):
# do something
class MyFacade:
def __init__(self, *args, **kwargs):
self.x = SOMETHING
self.obj = MyObject(*args, **kwargs)
def method1(self):
return self.obj.method1(self.x)
def method2(self, a):
return self.obj.method2(self.x, a)
def method3(self, a, b):
return self.obj.method3(self.x, a, b)
Now because I have several classes like MyObject, I'd like a generic way of creating a MyFacade for each of them without having to write code for each method (they all do more or less the same). Also if MyObject changes, I'd like MyFacade not being impacted and rather handle any interface change in MyObject transparently.
Thanks for the help!
EDIT:
This works but methods inherited from MyInterface raise TypeError because of the extra argument.
class MyObject:
def method1(self, x):
print(x)
def method2(self, x, a):
print(x, a)
def method3(self, x, a, b):
print(x, a, b)
class MyInterface:
def methodX(self):
print("YAY!")
class MyFacade(MyInterface, MyObject):
def __init__(self):
self.x= "WHATEVER"
def __getattribute__(self, item):
result = super().__getattribute__(item)
if callable(result):
return lambda *args, **kwargs: result(self.x, *args, **kwargs)
return result
EDIT:
I modified condition this way and now problem with MyInterface is gone:
if callable(result) and result.__name__ in MyObject.__dict__:
The obvious way of doing this is to use the fact that class and function names are variables and can be assigned so MyFacade could be defined as follows:
class MyFacade:
def __init__(self,obj, *args, **kwargs):
self.x = SOMETHING
self.obj = obj(*args, **kwargs)
def method1():
return self.obj.method1(self.x)
def method2(a):
return self.obj.method2(self.x, a)
def method3(a, b):
return self.obj.method1(self.x, a, b)
and the set-up call would be eg:
fasc = MyFscade(MyOject,*args,**kwargs)

Class inheritance in Python, super and overridden methods

Consider the following code:
class A:
def foo(self, a):
return a
def bar(self, a):
print(foo(a))
class B(A):
def foo(self, a):
return a[0]
Now calling B.bar(a) the result is print(a[0]), but what I want is print(a). More directly: I'd like that the calling of bar()in a child class uses the definition of foogiven in A even if overridden. How do i do that?
I believe this is what you are looking for:
class A(object):
def foo(self, a):
return a
def bar(self, a):
print(A.foo(self,a))
class B(A):
def foo(self, a):
return a[0]
or alternatively:
class A:
def foo(self, a):
return a
def bar(self, a):
print(self.foo(a))
class B(A):
def foo(self, a):
return super().foo(a)

python - refactoring - generalizing derived classes

I have following piece of code in Python. There are two classes A2 and B2 which share functions f1() and f2(). They differ in their base classes, deriving from A and B respectively.
I can see how to generalize this in C++ using templates. But I am not sure how to do this Python.
class A2(A):
def __init__(self):
A.__init__(self)
self._Z = Z('high')
def f1(self):
return self._Z.f1()
def f2(self):
return self._Z.f2()
# ... more functions ...
class B2(B):
def __init__(self):
B.__init__(self)
self._Z = Z('low')
def f1(self):
return self._Z.f1()
def f2(self):
return self._Z.f2()
# ... more functions ...
If I understand your question, you might try a mixin class:
class Mixin(object):
def f1(self):
return self._Z.f1()
def f2(self):
return self._Z.f2()
class A2(A, Mixin):
def __init__(self):
A.__init__(self)
self._Z = Z('high')
class B2(B, Mixin):
def __init__(self):
B.__init__(self)
self._Z = Z('low')

Elegant multiple inheritance in Python

I'm currently using this pattern to create a class C that inherits from A and B. I couldn't call super().__init__ from C since I would have to do the same in A and B, and the unexpected parameter would cause problems at the top level. I feel like this isn't very elegant. What is the proper way to do multiple inheritance in Python? I guess it is unusual to query the mro to find out if the superclass expects a parameter?
class A:
def __init__(self, something):
self.a = X(something)
def method_a(self):
self.a.go()
def method_ab(self):
self.a.go2()
class B:
def __init__(self, something):
self.b = X(something)
def method_b(self):
self.b.go()
def method_ab(self):
self.b.go2()
class C(A, B):
def __init__(self, something):
self.a_ = A(something)
self.b_ = B(something)
#property
def a(self):
return self.a_.a
#property
def b(self):
return self.b_.b
def method_ab(self):
for x in [self.a, self.b]:
x.method_ab()
The best solution I found was to use a base class to absorb the extra parameters:
class Base:
def __init__(self, something):
pass
def method_ab(self):
pass
class A(Base):
def __init__(self, something):
super().__init__(something)
self.a = X(something)
def method_a(self):
self.a.go()
def method_ab(self):
super().method_ab()
self.a.go()
class B(Base):
def __init__(self, something):
super().__init__(something)
self.b = X(something)
def method_b(self):
self.b.go()
def method_ab(self):
super().method_ab()
self.b.go()
class C(A, B):
pass

Categories

Resources