Passing instance during composition - python

I have a Common (or could call Base) class.
from enum import Enum
class Common:
def a(self, condition):
if condition == True:
return self.Keys.F.value
else:
return self.Keys.G.value
def b(self):
return Common.a(self, True) * 10
and multiple other classes, all of them use the Common class.
class KlassOne:
class Keys(Enum):
E = 0
F = 1
G = 2
def func(self, attribute):
w = Common.a(self, condition=bool(attribute))
x = Common.b(self)
return w, x
class KlassTwo:
class Keys(Enum):
E = 0
G = 1
F = 2
def func(self, attribute):
y = Common.a(self, condition=bool(attribute))
z = Common.b(self)
return y, z
how do I avoid the Common.a(self, ...) way of implementing this.
Is there an alternative to it?

You can instantiate your class :
class KlassOne:
def func(self, attribute):
common = Common()
w = common.a(condition=bool(attribute))
x = common.b()
return w, x

Your recent update to the question means that Common looks more like a mixin. (I would refactor b like this)
class Common:
def a(self, condition):
if condition == True:
return self.Keys.F.value
else:
return self.Keys.G.value
def b(self):
return self.a(True) * 10
The above Common does not need to import from enum.
Now your other classes can inherit from the above, just as a mixin:
from enum import Enum
class KlassOne(Common):
class Keys(Enum):
E = 0
F = 1
G = 2
def func(self, attribute):
w = self.a(condition=bool(attribute))
x = self.b()
return w, x

First, the Common.a(... is not necessary inside Common:
class Common:
def a(self, condition):
if condition == True:
return 1
else:
return 2
def b(self):
return self.a(True) * 10
Second, if you want to pass self of KlassOne to a method of class Common, then KlassOne actually should be an instance of class Common:
class KlassOne:
def func(self, attribute):
w = Common.a(self, condition=bool(attribute)) # <- here self is instance of KlassOne
x = Common.b(self)
return w, x
This is an argument strongly in favour of inheritance:
class KlassOne(Common):
def func(self, attribute):
w = self.a(condition=bool(attribute))
x = self.b()
return w, x
If you want to use composition, you would need to instantiate Common, e.g. like
class KlassOne:
def __init__(self):
self.common = Common()
def func(self, attribute):
w = self.common.a(condition=bool(attribute))
x = self.common.b()
return w, x

Related

python object building using multi-inheritance

I want to build an object dynamically which allow use to mix the class properties in whichever way they like base on multiple inheritance. This is the expected behaviour. These classes are dataclasses so there won't be many methods in them, mostly data properties.
class Foo():
def bar(self, x):
return x
class FooA(Foo):
def bar(self, x):
p = super().bar(x)
p += __class__.__name__
return p
class FooB(Foo):
def bar(self, x):
p = super().bar(x)
p += __class__.__name__
return p
class FooC(FooA, FooB):
def bar(self, x):
p = super().bar(x)
p += __class__.__name__
return p
f = FooC()
f.bar('S') # SFooBFooAFooC
However this code violate the DRY principle in broad daylight, hence I want to avoid the bar method completely, if there is no special operations in the current class.
Ideally I want something like
#bar_wrapper
class FooA(Foo):
pass
# OR
class FooA(Foo):
__metaclass__ = BarBase
Instead of this full implementation
class FooA(Foo):
def bar(self, x):
p = super().bar(x)
p += __class__.__name__
return p
Essentially is there a way that I extract the middle layer class information in a multi-level inheritance class through a decorator or metaclass (the two options that I can think of)? Anyone has any idea on how to do this?
Write a class decorator that adds the bar method to the class:
def bar_wrapper(cls):
def bar(self, x):
p = super(cls, self).bar(x)
p += cls.__name__
return p
bar.__module__ = cls.__module__
bar.__qualname__ = '{}.{}'.format(cls.__qualname__, bar.__name__)
cls.bar = bar
return cls
class Foo():
def bar(self, x):
return x
#bar_wrapper
class FooA(Foo):
pass
#bar_wrapper
class FooB(Foo):
pass
#bar_wrapper
class FooC(FooA, FooB):
pass
f = FooC()
print(f.bar('S')) # SFooBFooAFooC

Add non-lamda function to self of Python class

Adding lambda expression to self of a Python class is easy:
class Foo(object):
def __init__(self, x):
if x > 0:
self.eval = lambda x: x
else:
self.eval = lambda x: x**2
return
def compute(self, y):
return self.eval(y)
In my case, self.eval is somewhat more complex such that it doesn't fit into a one-line lambda. I need def. How can I assign self.eval with a defined function though?
For performance reasons, I would like to not store self.x = x and not move the if into compute.
You can define a function anywhere:
class Foo(object):
def __init__(self, x):
if x > 0:
def eval(y):
return y
else:
def eval(y):
return y**2
self.eval = eval
def compute(self, y):
return self.eval(y)
Python functions are first class objects. You can assign any function to a variable:
class Foo(object):
def __init__(self, x):
if x > 0:
self.eval = self.method1
else:
self.eval = self.method2
def method1(self, x):
return x
def method2(self, x):
return x * x
def compute(self, y):
return self.eval(y)
f1 = Foo(1)
print(f1.compute(10)) # 10 (method1)
f2 = Foo(-1)
print(f2.compute(10)) # 100 (method2)
At least in Python 3 it is trivial to add a method to an existing class. Just look at the following code:
>>> class A:
val = 2 # declare a class variable (will be the default value
>>> def func(self, x): # declare a function that will be added as a method
return self.val * x
>>> A.compute = func # add the compute method to class A
>>> a = A() # create an instance
>>> a.val # control the value of the member
2
>>> a.compute(3) # use the added method
6
>>> a.val=3 # change the value of the variable for the specific instance
>>> a.compute(4) # control that the new variable value is used
12

Is it possible to create a method by an argument

Say I have two functions
def do1(x, y):
return x + y
def do2(x, y):
return x - y
I can create a class like this
class foo(object):
def __init__(self, func):
self.func = func
abc = foo(func=do1)
abc.func(1, 1) # return 2
abc = foo(func=do2)
abc.func(1, 1) # return 0
Is it possible for me make abc.func to be a method rather than an attribute?
Thanks.
You can add a method to a class like so:
def do(self, x, y):
return x+y
class Foo(object0:
def __init(self):
pass
Foo.bar = do
a = Foo()
a.bar(1,2)
out> 3
Or to an instance:
def do2(x,y):
return x + y
a = Foo()
a.bar2 = do2
a.bar2(3,4)
out> 7

Python - Direct nested function call

I want to call a nested function directly, like this:
Template('/path/to/file').expect('key').to_be_in('second_key')
Template('/path/to/file').expect('key').to_be('value')
I tried this:
class Template(object):
def __init__(self, path):
self.content = json.load(open(path, 'r'))
def expect(self, a):
def to_be_in(b):
b = self.content[b]
return a in b
def to_be(b):
a = self.content[b]
return a == b
But I get the following error:
Template('~/template.json').expect('template_name').to_be_in('domains')
AttributeError: 'NoneType' object has no attribute 'to_be_in'
How to achieve that in Python ?
You have to return an object which provides a to_be_in member that is a function, to wit (example only):
class Template_Expect(object):
def __init__(self, template, a):
self.template = template
self.a = a
def to_be_in(self, b):
b = self.template.content[b]
return self.a in b
def to_be(self, b):
a = self.template.content[b]
return a == b
class Template(object):
def __init__(self, path):
self.content = json.load(open(path, 'r'))
def expect(self, a):
return Template_Expect(self, a)

What is the "metaclass" way to do this?

I want to write a program that accepts as input a number p and produces as output a type-constructor for a number that obeys integer arithmetic modulo p.
So far I have
def IntegersModP(p):
N = type('IntegersMod%d' % p, (), {})
def __init__(self, x): self.val = x % p
def __add__(a, b): return N(a.val + b.val)
... (more functions) ...
attrs = {'__init__': __init__, '__add__': __add__, ... }
for name, f in attrs.items():
setattr(N, name, f)
return N
This works fine, but I'd like to know what the Pythonic way to do this is, which I understand would use metaclasses.
Like this:
def IntegerModP(p): # class factory function
class IntegerModP(object):
def __init__(self, x):
self.val = x % p
def __add__(a, b):
return IntegerModP(a.val + b.val)
def __str__(self):
return str(self.val)
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, self.val)
IntegerModP.__name__ = 'IntegerMod%s' % p # rename created class
return IntegerModP
IntegerMod4 = IntegerModP(4)
i = IntegerMod4(3)
j = IntegerMod4(2)
print i + j # 1
print repr(i + j) # IntegerMod4(1)
Metaclasses are for when your class needs to behave differently from a normal class or when you want to alter the behavior of the class statement. Neither of those apply here, so there's really no need to use a metaclass. In fact, you could just have one ModularInteger class with instances that record their value and modulus, but assuming you don't want to do that, it's still easy to do this with an ordinary class statement:
def integers_mod_p(p):
class IntegerModP(object):
def __init__(self, n):
self.n = n % IntegerModP.p
def typecheck(self, other):
try:
if self.p != other.p:
raise TypeError
except AttributeError:
raise TypeError
def __add__(self, other):
self.typecheck(other)
return IntegerModP(self.n + other.n)
def __sub__(self, other):
...
IntegerModP.p = p
IntegerModP.__name__ = 'IntegerMod{}'.format(p)
return IntegerModP

Categories