I have a Cash class (derived from the Instrument class) which has a .manager class attribute. This class attribute (an instance of the Manager class), when it is initialized, needs to receive the class to which it is attached, as per below.
class Manager:
def __init__(self, instrument):
self.instrument = instrument #instrument is a class (a type)
def get(self, *args, **kwargs):
return self.instrument(30.99) #return an instance (e.g. ORM-like operation)
class Instrument:
pass
class Cash(Instrument):
manager = Manager(Cash) #this fails... as Cash isn't defined yet
def __init__(self, amount):
self.amount = amount
How do we achieve this, i.e. pass one's class to one of its own class attributes at definition?
If you have circular class/attributes, you can use functions that you call after instantiation, in my example add_A and add_B :
class A:
def __init__(self):
self.foo = 1
def add_B(self, b):
self.b = b
class B:
def __init__(self):
self.bar = 2
def add_A(self, a):
self.a = a
a = A()
b = B()
a.add_B(b)
print(a.b.bar)
# 2
b.add_A(a)
print(b.a.foo)
# 1
Related
lets say we have class A and it has one instance - x. How to make a child class of class A where I would be able to pass x as an argument and get all its parameters and pass it to child class object. precisely speaking I want to do something like this.
class A:
def __init__(self, parameter1, parameter2):
self.parameter1 = parameter1
self.parameter2 = parameter2
class B(A):
def __init__(self, Ainstance, someParameter):
super().__init__(**Ainstance.__dict__)
self.someParameter = someParameter
x = A(parameter1='1', parameter2='2')
x = B(x, someParameter='3')
print(x.parameter1)
print(x.parameter2)
print(x.someParameter)
the goal is to create a class where I would be able to get all the parameters of parent class object, and add my own attributes. The problem in the code above is I won't be able to do that with all classes because not all of them has __dict__ attribute.
I have this example code which I use to remind myself how to construct a proxy.
#soProxyPattern
class Example:
def __init__(self):
self.tag_name = 'name'
def foo(self):
return 'foo'
def bar(self, param):
return param
class Container:
def __init__(self, contained):
self.contained = contained
self.user_name = 'username'
def zoo(self):
return 0
def __getattr__(self, item):
if hasattr(self.contained, item):
return getattr(self.contained,item)
#raise item
c = Container(Example())
print(c.zoo())
print(c.foo())
print(c.bar('BAR'))
print(c.tag_name)
print(c.user_name)
The output is:
0
foo
BAR
name
username
This shows that Container can have its own attributes (methods or variables) which you can access over and above all of the attributes of the contained instance.
Instead of dict you could use the dir and getattr like this:
class A:
def __init__(self, parameter1, parameter2):
self.parameter1 = parameter1
self.parameter2 = parameter2
class B(A):
def __init__(self, Ainstance, someParameter):
parameters = {param: getattr(Ainstance, param) for param in dir(Ainstance) if not param.startswith("__")}
super().__init__(**parameters)
self.someParameter = someParameter
For a more detailed explanation see: Get all object attributes in Python?
I have a class Parent:
class Parent:
def __init__(self, foo):
self.foo = foo
I then have another class Child which extends Parent. But I want Child to take a pre-existing instance of parent and use this as the parent to inherit from (instead of creating a new instance of Parent with the same constructor parameters).
class Child(Parent):
def __init__(self, parent_instance):
""" Do something with parent_instance to set this as the parent instance """
def get_foo(self):
return self.foo
Then I would ideally be able to do:
p = Parent("bar")
c = Child(p)
print(c.get_foo()) # prints "bar"
You could copy the content of the parents's __dict__ to the child's. You can use vars() builtin function to do so, and the dictionary's update() method.
class Child(Parent):
def __init__(self, parent_instance):
vars(self).update(vars(parent_instance))
def get_foo(self):
return self.foo
p = Parent("bar")
c = Child(p)
print(c.get_foo())
# prints "bar"
You can use your own constructor - provide a classmethod that takes an instance of a parent.
class Parent:
def __init__(self, foo):
self.foo = foo
class Child(Parent):
def get_foo(self):
return self.foo
#classmethod
def from_parent(cls, parent_instance):
return cls(parent_instance.foo)
p = Parent('bar')
c = Child.from_parent(p)
c.get_foo()
I'm not sure inheritance is the right solution here as it breaks the LSP in the __init__ method.
Maybe parents and children just share a common interface.
I'd prefer something like (python3.8):
from typing import Protocol
class FoeAware(Protocol):
#property
def foe(self):
...
class Parent:
def __init__(self, foe):
self._foe = foe
#property
def foe(self):
return self._foe
class Child:
def __init__(self, parent: FoeAware):
self.parent = parent
#property
def foe(self):
return self.parent.foe
p = Parent("bar")
c = Child(p)
c.foe # bar
The key point is that it takes advantage of polymorphism with a common interface FoeAware, which is preferable to an inheritance tree.
Using getattr() to fetch the attribute from the parent instance
class Parent:
def __init__(self, foo):
self.foo = foo
class Child(Parent):
def __init__(self, parent_instance):
self.parent_instance = parent_instance
def get_foo(self):
return self.foo
def __getattr__(self, attr):
return getattr(self.parent_instance, attr)
par = Parent("bar")
ch = Child(par)
print(ch.get_foo())
#prints bar
When I try to allocate different function to different class members the last declared value gets overriden.
class Object:
def __init__(self, *args, **kwargs):
pass
class Service:
#staticmethod
def get_a_value():
return 1
#staticmethod
def get_b_value(*args, **kwargs):
return 2
def __init__(self, *args, **kwargs):
self.a = Object
self.b = Object
self.a.execute = self.get_a_value
self.b.execute = self.get_b_value
if __name__ == '__main__':
obj = Service()
print(obj.a().execute())
print(obj.b().execute())
The expected output is 1 & 2 but I'm getting both as 2. Not sure what I'm missing here. How can I make sure I can allocate different functions to a.execute and b.execute. Any help would be much appreciated.
what about creating specific objects for your a and b members, with a class deriving from Object:
class Object:
def __init__(self, *args, **kwargs):
pass
class Service:
#staticmethod
def get_a_value():
return 1
#staticmethod
def get_b_value(*args, **kwargs):
return 2
def __init__(self, *args, **kwargs):
class ObjectA(Object):
#staticmethod
def execute():
return Service.get_a_value()
class ObjectB(Object):
#staticmethod
def execute():
return Service.get_b_value()
self.a = ObjectA
self.b = ObjectB
if __name__ == '__main__':
obj = Service()
print(obj.a().execute())
print(obj.b().execute())
This prints
1
2
Of course this may become slightly more complex if the methods aren't static but this can be easily adapted in the example below where all methods are full non-static methods
class Service:
def get_a_value(self):
return self.__a_value
def get_b_value(self):
return self.__b_value
def __init__(self, *args, **kwargs):
self.__a_value = 1
self.__b_value = 2
class ObjectA(Object):
def execute(myself):
return self.get_a_value()
class ObjectB(Object):
def execute(myself):
return self.get_b_value()
You'll notice that self used in execute methods refer to instance of Service (hence the myself first argument in child classes). It works as well, even if no method is static, and can access values of the instance.
With that, you can create full-fledged object interfaces.
It is because obj.a and obj.b contain both a reference to the same class.
So everything you modify on obj.a will be reflected in obj.b.
What you probably wanted to do is :
def __init__(self, *args, **kwargs):
self.a = Object()
self.b = Object()
self.a.execute = self.get_a_value
self.b.execute = self.get_b_value
I am making a python program which is using classes, I want one class to only selectively inherit from another e.g:
class X(object):
def __init__(self):
self.hello = 'hello'
class Y(object):
def __init__(self):
self.moo = 'moo'
class Z():
def __init__(self, mode):
if mode == 'Y':
# Class will now Inherit from Y
elif mode == 'X':
# Class will now Inherit for X
How can I do this without making another class?
In Python classes can be created at run-time:
class X(object):
def __init__(self):
self.hello = 'hello'
class Y(object):
def __init__(self):
self.moo = 'moo'
def create_class_Z(mode):
base_class = globals()[mode]
class Z(base_class):
def __init__(self):
base_class.__init__(self)
return Z
ZX = create_class_Z('X')
zx = ZX()
print(zx.hello)
ZY = create_class_Z('Y')
zy = ZY()
print(zy.moo)
You can do this by overriding __new__ and changing the cls passed in (you're creating a new type by appending X or Y as a base class):
class X(object):
def __init__(self):
self.hello = 'hello'
class Y(object):
def __init__(self):
self.moo = 'moo'
class Z(object):
def __new__(cls, mode):
mixin = {'X': X, 'Y': Y}[mode]
cls = type(cls.__name__ + '+' + mixin.__name__, (cls, mixin), {})
return super(Z, cls).__new__(cls)
def __init__(self, mode, *args, **kwargs):
super(Z, self).__init__(*args, **kwargs)
Note that you need to bypass Z.__new__ using super to avoid infinite recursion; this is the standard pattern for __new__ special override methods.
I think you'd better define two members within Z,one is a class instance of X,another is a instance of Y.You can get the associated information stored in these instances while use different mode.
A solution using type:
class _Z(): pass #rename your class Z to this
def Z(mode): #this function acts as the constructor for class Z
classes = {'X': X, 'Y': Y, 'Foo': Bar} #map the mode argument to the base cls
#create a new type with base classes Z and the class determined by mode
cls = type('Z', (_Z, classes[mode]), {})
#instantiate the class and return the instance
return cls()
I want to add some attributes and methods into various class. The methods and attributes that I have to add are the same but not the class to assign them, so I want to construct a class who assign new methods and attributes for a class given in argument.
I try this but it's not working:
(I know that is a very wrong way to try to assign something to self, it's just to show what I want to do)
class A:
def __init__(self):
self.a = 'a'
def getattA(self):
return self.a
class B:
def __init__(self, parent) :
self = parent
# This is working :
print self.getattA()
def getattB(self):
return self.getattA()
insta = A()
instb = B(insta)
# This is not working :
print instb.getattB()
The result is :
a
Traceback (most recent call last):
File "D:\Documents and settings\Bureau\merge.py", line 22, in <module>
print instb.getattB()
File "D:\Documents and settings\Bureau\merge.py", line 16, in getattB
return self.getattA()
AttributeError: B instance has no attribute 'getattA'
And I expected to got 'a' for the call of instb.gettattB()
To resume I want to inherit class B from class A giving class A in argument of class B because my class B will be a subclass of various class, not always A.
The Best answer is in the comments, it was useful for me so I decided to show it in an answer (thank to sr2222):
The way to dynamicaly declare inherance in Python is the type() built-in function.
For my example :
class A(object) :
def __init__(self, args):
self.a = 'a'
self.args = args
def getattA(self):
return self.a, self.args
class B(object) :
b = 'b'
def __init__(self, args) :
self.b_init = args
def getattB(self):
return self.b
C = type('C', (A,B), dict(c='c'))
instc = C('args')
print 'attributes :', instc.a, instc.args, instc.b, instc.c
print 'methodes :', instc.getattA(), instc.getattB()
print instc.b_init
The code return :
attributes : a args b c
methodes : ('a', 'args') b
Traceback (most recent call last):
File "D:\Documents and settings\Bureau\merge2.py", line 24, in <module>
print instc.b_init
AttributeError: 'C' object has no attribute 'b_init'
My class C inerhite attributes and methods of class A and class B and we add c attribute. With the instanciation of C (instc = C('args')) The init for A is call but not for B.
Very useful for me because I have to add some attributes and methodes (the same) on different class.
I was having trouble with calling different constructors, using super doesn't necessarily make sense in a case like this, I opted to inherit and call each constructor on the current object manually:
class Foo(object):
def __init__(self, foonum):
super(Foo, self).__init__()
self.foonum = foonum
class Bar(object):
def __init__(self, barnum):
super(Bar, self).__init__()
self.barnum = barnum
class DiamondProblem(Foo, Bar):
# Arg order don't matter, since we call the `__init__`'s ourself.
def __init__(self, barnum, mynum, foonum):
Foo.__init__(self, foonum)
Bar.__init__(self, barnum)
self.mynum = mynum
How about this?
class A:
def __init__(self):
self.a = 'a'
def getatt(self):
return self.a
class B:
def __init__(self, parent) :
self.parent = parent
def __getattr__(self, attr):
return getattr(self.parent, attr)
def getattB(self):
return self.parent.getatt()
insta = A()
instb = B(insta)
print instb.getattB()
print instb.getatt()
But method in class A can not access attr in class B.
Another way:
import functools
class A:
def __init__(self):
self.a = 'a'
def getatt(self):
return self.a
class B:
def __init__(self, parent):
for attr, val in parent.__dict__.iteritems():
if attr.startswith("__"): continue
self.__dict__[attr] = val
for attr, val in parent.__class__.__dict__.iteritems():
if attr.startswith("__"): continue
if not callable(val): continue
self.__dict__[attr] = functools.partial(val, self)
def getattB(self):
return self.getatt()
insta = A()
instb = B(insta)
print instb.__dict__
print instb.getattB()
print instb.getatt()
Slow with init but call fast.
Since B is not a subclass of A, there is no path in B to getatt() in A
I guess i have a easier method
class fruit1:
def __init__(self):
self.name = "apple"
self.color = "blue"
class fruit2:
def __init__(self):
self.name = "banana"
self.size = 100
def merge(ob1, ob2):
ob1.__dict__.update(ob2.__dict__)
return ob1
f1 = fruit1()
f2 = fruit2()
fruit = merge(f1, f2)
print("name:",fruit.name," color:",fruit.color, " size:",fruit.size)
#output: name: banana color: blue size: 100
I'm not certain what you are trying to do, but the code below is giving my the output I think you are expecting. notice:
a is initialized outside the constructor in A
B is declared as a subclass of A
Code:
class A:
a='' #Initialize a
def __init__(self):
self.a = 'a'
def getatt(self):
return self.a
class B(A): #Declare B as subclass
def __init__(self, parent) :
self = parent
print self.getatt()
def getattB(self):
return self.getatt()
insta = A()
instb = B(insta)
print instb.getattB()
Helper function below conducts the merge of the dataclass instances, the attributes orders is derived from *args order:
from dataclasses import dataclass
#dataclass
class A:
foo: str
bar: str
def merge_dataclasses(*args):
if len({e.__class__.__name__ for e in args}) > 1:
raise NotImplementedError('Merge of non-homogeneous entries no allowed.')
data = {}
for entry in args[::-1]:
data.update(vars(entry))
return entry.__class__(**data)
print(merge_dataclasses(A(foo='f', bar='bar'), A(foo='b_foo', bar='b_bar')))
One easy way to merge two or more classes is through the tool set dyndesign:
from dyndesign import mergeclasses
class Base:
def __init__(self, init_value):
self.param = init_value
def m1(self):
print(f"Method `m1` of class `Base`, and {self.param=}")
def m2(self):
print(f"Method `m2` of class `Base`")
class Ext:
def m1(self):
print(f"Method `m1` of class `Ext`, and {self.param=}")
MergedClass = mergeclasses(Base, Ext)
merged_instance = MergedClass("INITIAL VALUE")
merged_instance.m1()
# Method `m1` of class `Ext`, and self.param='INITIAL VALUE'
merged_instance.m2()
# Method `m2` of class `Base`
Emphasizing ThorSummoner's's answer and Hong's comment; this method appears to be cleaner than the excepted answer. Notice Hong's use of super().init(self) in all but the last object added to the merge class.
class Foo(object):
def __init__(self, foonum):
super(Foo, self).__init__(self)
self.foonum = foonum
class Bar(object):
def __init__(self, barnum):
super(Bar, self).__init__(self)
self.barnum = barnum
class Oops(object):
def __init__(self, oopsnum):
super(Oops, self).__init__()
self.oopsnum = oopsnum
class DiamondProblem(Foo, Bar, Oops):
def __init__(self, mynum, foonum, barnum, oopsnum):
Foo.__init__(self, foonum)
Bar.__init__(self, barnum)
Oops.__init__(self, oopsnum)
self.mynum = mynum
def main():
dia = DiamondProblem(1, 10, 20, 30)
print(f"mynum: {dia.mynum}")
print(f"foonum: {dia.foonum}")
print(f"barnum: {dia.barnum}")
print(f"oopsnum: {dia.oopsnum}")