I have a BaseEntity class, which defines a bunch (a lot) of non-required properties and has most of functionality. I extend this class in two others, which have some extra methods, as well as initialize one required property.
class BaseEntity(object):
def __init__(self, request_url):
self.clearAllFilters()
super(BaseEntity, self).__init__(request_url=request_url)
#property
def filter1(self):
return self.filter1
#filter1.setter
def filter1(self, some_value):
self.filter1 = some_value
...
def clearAllFilters(self):
self.filter1 = None
self.filter2 = None
...
def someCommonAction1(self):
...
class DefinedEntity1(BaseEntity):
def __init__(self):
super(BaseEntity, self).__init__(request_url="someUrl1")
def foo():
...
class DefinedEntity2(BaseEntity):
def __init__(self):
super(ConsensusSequenceApi, self).__init__(request_url="someUrl2")
def bar(self):
...
What I would like is to initialize a BaseEntity object once, with all the filters specified, and then use it to create each of the DefinedEntities, i.e.
baseObject = BaseEntity(None)
baseObject.filter1 = "boo"
baseObject.filter2 = "moo"
entity1 = baseObject.create(DefinedEntity1)
Looking for pythonic ideas, since I've just switched from statically typed language and still trying to grasp the power of python.
One way to do it:
import copy
class A(object):
def __init__(self, sth, blah):
self.sth = sth
self.blah = blah
def do_sth(self):
print(self.sth, self.blah)
class B(A):
def __init__(self, param):
self.param = param
def do_sth(self):
print(self.param, self.sth, self.blah)
a = A("one", "two")
almost_b = copy.deepcopy(a)
almost_b.__class__ = B
B.__init__(almost_b, "three")
almost_b.do_sth() # it would print "three one two"
Keep in mind that Python is an extremely open language with lot of dynamic modification possibilities and it is better not to abuse them. From clean code point of view I would use just a plain old call to superconstructor.
I had the same problem as the OP and was able to use the idea from Radosław Łazarz above of explicitly setting the class attribute of the object to the subclass, but without the deep copy:
class A:
def __init__(a) : pass
def amethod(a) : return 'aresult'
class B(A):
def __init__(b) : pass
def bmethod(self) : return 'bresult'
a=A()
print(f"{a} of class {a.__class__} is {'' if isinstance(a,B) else ' not'} an instance of B")
a.__class__=B # here is where the magic happens!
print(f"{a} of class {a.__class__} is {'' if isinstance(a,B) else ' not'} an instance of B")
print(f"a.amethod()={a.amethod()} a.bmethod()={a.bmethod()}")
Output:
<__main__.A object at 0x00000169F74DBE88> of class <class '__main__.A'> is not an instance of B
<__main__.B object at 0x00000169F74DBE88> of class <class '__main__.B'> is an instance of B
a.amethod()=aresult a.bmethod()=bresult
Related
Is there a way in python to pass a function call to an inner object, maybe through a decorator or wrapper? In the example below, class A holds a list of class B objects, and one of the class B objects is selected as the active object. I want class A to function as a passthrough, just identifying which of the class B objects that the call goes to. However, class A doesn't know what type of class it is going to hold beforehand, so I can't just add a set_var function to class A. It has to work for any generic function that class B has. It will only have one type of class in its objects list, so it could take class B as an input when it is instantiated and dynamically create functions, if that's a possibility. The client wouldn't know whether it's dealing with class A or class B. The code below is as far as I got.
class A:
def __init__(self):
self.objects = []
self.current_object = 0
def add_object(self, object):
self.objects.append(object)
class B:
def __init__(self):
self.var = 10
def set_var(self, new_var):
self.var = new_var
a_obj = A()
b_obj1 = B()
b_obj2 = B()
a_obj.add_object(b_obj1)
a_obj.add_object(b_obj2)
a_obj.set_var(100)
You could use the generic __getattr__ to delegate to the wrapped object.
class A:
def __init__(self):
self.objects = []
self.current_object = 0
def add_object(self, obj):
self.objects.append(obj)
self.current_object = obj
def __getattr__(self, name):
return getattr(self.current_object, name)
class B:
def __init__(self):
self.var = 10
def set_var(self, new_var):
self.var = new_var
a_obj = A()
b_obj1 = B()
b_obj2 = B()
a_obj.add_object(b_obj1)
a_obj.add_object(b_obj2)
a_obj.set_var(100)
print(b_obj2.var)
That will print "100".
You will still get an AttributeError if the wrapped object doesn't have the expected method.
It was interesting to look at this, it is intentionally rough but it does indeed allow you to call one the B instance's set_var methods.
The code below uses sets as a quick and dirty way to see the difference in callable methods, and if there is; it sets the attribute based on that name. Binding the method to the A instance.
This would only bind set_var once from the first object given.
def add_object(self, object):
self.objects.append(object)
B_methods = set([m for m in dir(object) if callable(getattr(object, m))])
A_methods = set([m for m in dir(self) if callable(getattr(self, m))])
to_set = B_methods.difference(A_methods)
for method in to_set:
setattr(self, method, getattr(object, method))
I have a class A and a class B derived from A.
After creating an instance of class A with many operations performed, I now want to serialize that specific object. Let's call that object A_instance.
When initializing class B, how can I tell B that it's base object should be A_instance?
Within B's init i want to decide whether it should normally execute super().__init__(...) or setting the base object directly to A_instance.
Here is a code example which makes my question hopefully clear:
class A():
def __init__(self, a=1):
self.a = a
self.message = "Hello, I'm class A"
myA = A(15)
class B(A):
def __init__(self, b=2, my_base=None):
if my_base:
# what should i code here? maybe someting like super().super_object = my_base
pass
else:
super(B, self).__init__()
self.b = b
self.message = "Hello, I'm class B inherited from A"
#Then the above code should result in something like:
myB = B(my_base=myA)
assert myB.a == myA.a
A similar if not even the same question for C++ can be found here:
set the base object of derived object?
I have a question which is more regarding OOP in general rather than python specific.
Is ist possible to store instances of ClassA in instance of ClassB without a specific method, i.e. by some kind of inheritance.
Example: let's say I have one Model class and one Variable class
class Model():
def __init__(self):
self.vars = []
def _update_vars(self,Variable):
self.vars.append(Variable)
class Variable(Model):
def __init__(self,**kwargs):
self.__dict__.update(kwargs)
Is it now possible to call _update_vars whenever an instance of variable is being created.
So if I do something like this:
mdl = Model()
varA = Variable(...)
varB = Variable(...)
that mdl.vars would now include varA and varB.
I know that I could easily do this by passing the variables as an argument to a "public" method of Model. So I am not looking for
mdl.update_vars(varA)
So my two questions are:
is this possible?
if yes: would this very non-standard OOP programming?
Thanks for your help!
That's not how class inheritance is supposed to work. You only want to inherit something if the child class is going to make use of a good amount of the attributes/methods within the parent class. If the child class has a markedly different structure it should be a class of its own.
In either case, as mentioned by #jasonharper, at some point you would need to give direction as to which Variable instance belongs in which Model instance, so you're likely to end up with something like these:
varA = Variable(mdl, ...)
# or this
mdl.varA = Variable(...)
With the first way, you would maintain the method on your Variable class:
class Foo:
def __init__(self):
self.vars = []
class Bar:
def __init__(self, foo_instance, **kwargs):
foo_instance.vars.append(self)
f = Foo()
b = Bar(f, hello='hey')
f.vars
# [<__main__.Bar object at 0x03F6B4B0>]
With the second way, you can append the Variable instances into a list each time it's added:
class Foo:
def __init__(self):
self.vars = []
def __setattr__(self, name, val):
self.__dict__.update({name: val})
if not name == 'vars': # to prevent a recursive loop
self.vars.append(val)
f = Foo()
f.vars
# []
f.a = 'bar'
f.vars
# ['bar']
Of course, an easier way would be to just look directly into the __dict__ each time you want vars:
class Bar:
#property
def vars(self):
# Or you can return .items() if you want both the name and the value
return list(self.__dict__.values())
b = Bar()
b.a = 'hello'
b.vars
# ['hello']
Both of these will work the same even if you assigned the attributes with your own class instances.
You can use super() for this and pass the instance to the parent
class Model():
vars = []
def __init__(self, other=None):
if other:
self.vars.append(other)
class Variable(Model):
def __init__(self, a):
self.a = a
super().__init__(self)
mdl = Model()
varA = Variable(3)
varB = Variable(4)
print(mdl.vars)
I am trying to understand python's class inheritance methods and I have some troubles figuring out how to do the following:
How can I inherit a method from a class conditional on the child's input?
I have tried the following code below without much success.
class A(object):
def __init__(self, path):
self.path = path
def something(self):
print("Function %s" % self.path)
class B(object):
def __init__(self, path):
self.path = path
self.c = 'something'
def something(self):
print('%s function with %s' % (self.path, self.c))
class C(A, B):
def __init__(self, path):
# super(C, self).__init__(path)
if path=='A':
A.__init__(self, path)
if path=='B':
B.__init__(self, path)
print('class: %s' % self.path)
if __name__ == '__main__':
C('A')
out = C('B')
out.something()
I get the following output:
class: A
class: B
Function B
While I would like to see:
class: A
class: B
B function with something
I guess the reason why A.something() is used (instead of B.something()) has to do with the python's MRO.
Calling __init__ on either parent class does not change the inheritance structure of your classes, no. You are only changing what initialiser method is run in addition to C.__init__ when an instance is created. C inherits from both A and B, and all methods of B are shadowed by those on A due to the order of inheritance.
If you need to alter class inheritance based on a value in the constructor, create two separate classes, with different structures. Then provide a different callable as the API to create an instance:
class CA(A):
# just inherit __init__, no need to override
class CB(B):
# just inherit __init__, no need to override
def C(path):
# create an instance of a class based on the value of path
class_map = {'A': CA, 'B': CB}
return class_map[path](path)
The user of your API still has name C() to call; C('A') produces an instance of a different class from C('B'), but they both implement the same interface so this doesn't matter to the caller.
If you have to have a common 'C' class to use in isinstance() or issubclass() tests, you could mix one in, and use the __new__ method to override what subclass is returned:
class C:
def __new__(cls, path):
if cls is not C:
# for inherited classes, not C itself
return super().__new__(cls)
class_map = {'A': CA, 'B': CB}
cls = class_map[path]
# this is a subclass of C, so __init__ will be called on it
return cls.__new__(cls, path)
class CA(C, A):
# just inherit __init__, no need to override
pass
class CB(C, B):
# just inherit __init__, no need to override
pass
__new__ is called to construct the new instance object; if the __new__ method returns an instance of the class (or a subclass thereof) then __init__ will automatically be called on that new instance object. This is why C.__new__() returns the result of CA.__new__() or CB.__new__(); __init__ is going to be called for you.
Demo of the latter:
>>> C('A').something()
Function A
>>> C('B').something()
B function with something
>>> isinstance(C('A'), C)
True
>>> isinstance(C('B'), C)
True
>>> isinstance(C('A'), A)
True
>>> isinstance(C('A'), B)
False
If neither of these options are workable for your specific usecase, you'd have to add more routing in a new somemethod() implementation on C, which then calls either A.something(self) or B.something(self) based on self.path. This becomes cumbersome really quickly when you have to do this for every single method, but a decorator could help there:
from functools import wraps
def pathrouted(f):
#wraps
def wrapped(self, *args, **kwargs):
# call the wrapped version first, ignore return value, in case this
# sets self.path or has other side effects
f(self, *args, **kwargs)
# then pick the class from the MRO as named by path, and call the
# original version
cls = next(c for c in type(self).__mro__ if c.__name__ == self.path)
return getattr(cls, f.__name__)(self, *args, **kwargs)
return wrapped
then use that on empty methods on your class:
class C(A, B):
#pathrouted
def __init__(self, path):
self.path = path
# either A.__init__ or B.__init__ will be called next
#pathrouted
def something(self):
pass # doesn't matter, A.something or B.something is called too
This is, however, becoming very unpythonic and ugly.
While Martijn's answer is (as usual) close to perfect, I'd just like to point out that from a design POV, inheritance is the wrong tool here.
Remember that implementation inheritance is actually a static and somehow restricted kind of composition/delegation, so as soon as you want something more dynamic the proper design is to eschew inheritance and go for full composition/delegation, canonical examples being the State and the Strategy patterns. Applied to your example, this might look something like:
class C(object):
def __init__(self, strategy):
self.strategy = strategy
def something(self):
return self.strategy.something(self)
class AStrategy(object):
def something(self, owner):
print("Function A")
class BStrategy(object):
def __init__(self):
self.c = "something"
def something(self, owner):
print("B function with %s" % self.c)
if __name__ == '__main__':
a = C(AStrategy())
a.something()
b = C(BStrategy())
b.something()
Then if you need to allow the user to specify the strategy by name (as string), you can add the factory pattern to the solution
STRATEGIES = {
"A": AStrategy,
"B": BStrategy,
}
def cfactory(strategy_name):
try:
strategy_class = STRATEGIES[strategy_name]
except KeyError:
raise ValueError("'%s' is not a valid strategy" % strategy_name)
return C(strategy_class())
if __name__ == '__main__':
a = cfactory("A")
a.something()
b = cfactory("B")
b.something()
Martijn's answer explained how to choose an object inheriting from one of two classes. Python also allows to easily forward a method to a different class:
>>> class C:
parents = { 'A': A, 'B': B }
def __init__(self, path):
self.parent = C.parents[path]
self.parent.__init__(self, path) # forward object initialization
def something(self):
self.parent.something(self) # forward something method
>>> ca = C('A')
>>> cb = C('B')
>>> ca.something()
Function A
>>> cb.something()
B function with something
>>> ca.path
'A'
>>> cb.path
'B'
>>> cb.c
'something'
>>> ca.c
Traceback (most recent call last):
File "<pyshell#46>", line 1, in <module>
ca.c
AttributeError: 'C' object has no attribute 'c'
>>>
But here class C does not inherit from A or B:
>>> C.__mro__
(<class '__main__.C'>, <class 'object'>)
Below is my original solution using monkey patching:
>>> class C:
parents = { 'A': A, 'B': B }
def __init__(self, path):
parent = C.parents[path]
parent.__init__(self, path) # forward object initialization
self.something = lambda : parent.something(self) # "borrow" something method
it avoids the parent attribute in C class, but is less readable...
I'm a beginner in Python and PySide. Can someone explain me how to recognize what is an object constructor and what is a method in this class (e.g. QLCDNumber(self) vs addWidget(argv)) and therefore why not calling self.vbox instead of vbox?
import sys
from PySide import QtGui, QtCore
class App(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.init_ui()
def init_ui(self):
lcd = QtGui.QLCDNumber(self)
sld = QtGui.QSlider(QtCore.Qt.Horizontal, self)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(lcd)
vbox.addWidget(sld)
The difference between "methods" and "object constructors" in Python is very thin. You must be getting thoroughly confused with Java here.
Consider this:
class A():
def __init__(self, bar):
baz = bar + bar
self.egg = baz + baz
def B(tuna):
return A(tuna)
What happens is baz is a mere variable and only egg hangs around after A.__init__() ends.
>>> A("foo").egg
"foofoofoofoo"
>>> A("foo").baz # exception
Also, the return values of A() and B() are indistinguishable.
In Python, way moreso than Java, everything is an object and with a few corner cases there is no distinction between functions and methods. If you really really really did need to check, this is the way to go:
>>> import types
>>> type(A) == types.ClassType and type(B) != types.ClassType
True
>>> type(A) != types.FunctionType and type(B) == types.FunctionType
True
>>> type(A.__init__) == types.MethodType and type(B) != types.MethodType
True
...but the need to do such introspection is quite rare.
Class constructors are defined by the method __init__. All non-static class methods (including the constructor) take a reference to the object itself in the form the self parameter, which is the first parameter passed.
You'd create a new instance of the App class by doing the following:
app = App()
Then to call the method init_ui you'd do the following:
app.init_ui()
If lcd, sld and vbox are all member variables of the App class then you'll need to access them as self.vbox within the methods.
Constructor __init__() is called when you initialise the class
class example:
def __init__(self):
print("example")
def init(self):
print("example No. 2")
So:
>>>a = example
... "example"
>>>a.init()
... "example No. 2"
The self is something that class have stored inside itself, not globaly but it will not 'disaper'
class Human:
def __init__(self, gender, name):
self.age = 0
self.gender = gender
self.name = name
def aging(self):
self.age += 1
humans = []
humans.append(Human("male", "Jack")) # his age is 0 and gender is male
humans.append(Human("female", "Jesica"))
for human in humans:
human.aging() # age is increasing