Suppose I have the following example:
import uuid
class A:
def __init__(self):
self.id = uuid.uuid4().hex
class B(A):
def __init__(self):
super().__init__()
self.print_id()
def print_id(self):
print(self.id)
class C(A):
def __init__(self):
super().__init__()
self.print_id()
def print_id(self):
print(self.id)
We have class B and C that are inheriting A. Once B or C are instantiated, they will print the unique ID created in the super class. The issue I am running into here is that each time B or C is instantiated, there is a brand new id created for class A. I would like to print/use the SAME ID for both class B and C. In other words, I only want to have one instance of class A to be used for B and C. Without involving any sort of logic surrounding singletons, how can I achieve this? How can class C know that class B has already initialized class A, therefore an ID already exists? I am attempting to create a base class that is initialized only once, and that ID is inherited by all the sub classes. Any help here would be appreciated.
You can use a class attribute
e.g.
class A:
static_id = uuid.uuid4().hex
def __init__(self):
pass
The rest of the code will be the same.
I changed the name of the id member, because it shadowed the name of a built-in function.
(This solution smells to me a little, but I do not understand your problem enough to suggest anything better).
Related
I have two objects one inherits from the other and the only difference between them is a few attribute fields:
class Parent:
def __init__(self,a, b):
self.a = a
self.b = b
def methodA(self):
# do something
pass
class Child(Parent):
def __init__(self,c,**kwargs):
self.c = c
super().__init__(**kwargs)
I have an instance of the parent object and I want to find a fast way in python to create an instance of the child object which only has one additional field by using the already existing parent object.
Is there a python way or module that lets you do that easily. IN my real code the parent class has hundreds of fields and it is a bit inefficient to just reassign its value.
The canonical solution is to add a class method to Child that works as a constructor. It takes a Parent instance and returns the Child instance with the proper attributes.
For example:
class Parent:
def __init__(self,a, b):
self.a = a
self.b = b
class Child(Parent):
def __init__(self,c,**kwargs):
self.c = c
super().__init__(**kwargs)
#classmethod
def from_parent(cls, parent, c):
return cls(a=parent.a, b=parent.b, c=c)
p = Parent(a=1, b=2)
c = Child.from_parent(parent=p, c=3)
print(c.a, c.b, c.c) # output: 1 2 3
I would argue that your Parent class having hundreds of attributes is irrelevant to the answer. Yes, it's tedious having to explicitly write every attribute of the Parent instance in the from_parent method, but that's simply a limitation of having a class with that many attributes anyway. Possibly, a better design choice would be to encapsulate groups of Parent attributes into proper classes, so that only those instances need to be delivered to the Child class upon initialization.
Ok the other suggestions for making a method that takes in parent attributes and creates a child object is ok but adds unnecessary code I think. I made this solution, which I ended up using. It doesnt accept the parent object directly in as an argument but it is more concise I think:
class Parent:
def __init__(self, a, b):
self.a = a
self.b = b
class Child(Parent):
def __init__(self,c, **kwargs):
self.c = c
super().__init__(**kwargs)
# So if I start with this parent object
parent_args = {"a":23,"b":"iuhsdg"}
parent =Parent(**parent_args)
# I then make child with all the parent attributes plus some more
child_args = {"c":567}
child_args.update(vars(parent))
child = Child(**child_args)
I understand that __init__() is the constructor for an instance of the class. It is called whenever a class is instantiated. There is also the concept of class variables -- variables that belong to the class and shared by all instances. For example:
class A(object):
a = 1
b = [] #a and b are shared by all instances of class A
But the problem is that sometimes it takes more code to initialize a and b than the one lines showing above. Therefore there is a need for 'class level constructor.' I wonder, though, if there is such a thing.
You can just do something like
class A(object):
# .......
var = input()
var += 10
# ecc.
A.b = var
I'd like to be able to extend a class without inheriting one of the class variables.
Given this scenario:
class A:
aliases=['a','ay']
class B(A):
pass
print(B.aliases)
I would rather get an error that B has not defined the aliases variable rather than have B accidentally called ay.
One could imagine a solution where aliases becomes a member of the instantiated object (self.aliases) and is set in __init__ but I really want to be able to access the aliases using the cls object rather than an instance of the class.
Any suggestions?
Python does not have REALY private attributes. But you can define it with a double underscore (__):
class A:
__aliases=['a','ay']
class B(A):
pass
print(B.__aliases) # yields AttributeError
But you still will be able to access it with:
print(B._A__aliases)
This is kindof a ganky work around but here you go:
class K:
def __init__(self):
self.mems = dir(self)
def defaultMembers():
k = K()
return(k.mems)
class A:
aliases=['a','ay']
class B(A):
def __init__(self):
for k in set(dir(self))-set(defaultMembers()):
print("removing "+k)
setattr(self, k, None)
a = A()
b = B()
print(b.aliases)
#None
print(a.aliases)
#['a','ay']
I guess all you really need is the setattr(self, "aliases", None) still this results in a None and not a non-variable. Unfortunately calsses don't support deletion because I tried to use del first.
I'm stuck on this point about class inheritance, and I haven't been able to figure out a clean way forward. I have some base class:
class Foo:
""" Parent class. """
def __init__(self,a,b):
self.a = a
self.b = b
def product(self):
return self.a * self.b
This class contains information I've loaded in from some data file. I want to generate different kinds of information related to this data, using class properties to store that information. For example, if I wanted to create a report that tells me the quotient of a and b, I would want to create something like:
class Bar(Foo):
""" Child class. """
def __init__(self,foo_object):
# What I want to avoid:
self.a = foo_object.a
self.b = foo_object.b
def quotient(self):
return self.a / self.b
Obviously there are many more class properties in my real application. It becomes very tedious to assign all of the properties from the Foo object into the new Bar object.
Is there a more elegant way to "extend" a Foo object into a Bar object once the Foo object has already been created?
EDIT:
Sorry if I didn't state my objective clearly enough; I see that there's some confusion about what I'm asking for. I've already created a Foo object with a number of properties. I want to create a child class of Foo, called Bar, later, that contains those properties but also some additional properties that are specific to one "area" of my application.
So, I want to be able to pass in an already instantiated Foo object, and pass the values of its properties into identical properties in Bar, without doing this manually item-by-item.
I believe Flob's answer is what I'm looking for. Thank you!
You can inherit the Information directly by initiating the parent class inside the child class. Once you have created an instance of the parent class, you can Access all it's properties by using vars(object), which will return a dictionary of all properties assiciated with the object. For example, let's say you have a class Foo:
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
and test_parent is an instance of this class.
test_parent = Foo(a='Hello', b='World')
now, when creating the Bar child class, do it like this:
class Bar(Foo):
def __init__(self, foo_object):
a, b = vars(foo_object).values() #get all properties of parent class object
Foo.__init__(self, a, b) # initiate parent class
def say_hello(self):
print('{} {}'.format(self.a, self.b))
Create an instance of the Bar class and call say_hello:
test_child = Bar(test_parent)
test_child.say_hello()
Output:
"Hello World"
I'm not sure I understand what you mean by "once the Foo object has already been created".
For initialization of the attributes defined by the parent class, use this:
class Bar(Foo):
""" Child class. """
def __init__(self,a,b):
super().__init__(a,b)
def quotient(self):
return self.a / self.b
Let the __init__() method of the super-class continue to do its job of initializing a and b.
Note that b = B() creates only one object, not two.
In the code you posted, Bar.__init__() seems to take a Foo object as one of its arguments. Technically, that is a case of wrapping a Foo object in a Bar object -- and if you're doing that, there really is no need for Bar to be a child class of Foo:
class Bar:
""" Wrapper class. """
def __init__(self, foo_object):
self.foo_object = foo_object
def quotient(self):
return self.foo_object.a / self.foo_object.b
It is possible to change the class of the object after it is created. Instead of unpacking the contents of the object into a new one, you change the class that it uses to look up methods:
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
class Bar(Foo):
def quotient(self):
return self.a/self.b
f = Foo(1, 2)
f.__class__ = Bar
f.quotient() # 0.5
This usually isn't necessary (I woudln't recommend using it here). Instead, you could create a Bar object directly:
b = Bar(1, 2)
b.quotient()
Bar inherits the __init__ method of Foo, so you don't have to redefine it.
Another option is to use a function that's not a method:
def quotient(obj):
return obj.a/obj.b
Now you can compute quotient(Foo(1,2)) even though your Foo object doesn't know about the quotient function.
A class can inherit from a base class, but an object cannot inherit from another object. It can either be a copy (with possibly additional attributes) or wraps the original object. The first case is for a true inheritance strategy (the child instance has to be an instance of the base class and must initialize itself), the second if for an aggregation or containment strategy.
But beware, there are some caveats with the second one, mainly because the child object is not an instance of the base class (isinstance(child, Foo) is false). That means that there is no one size fits all way here, and you will have to choose one pattern, inheritance vs aggregation.
Let B inherit from A. Suppose that some of B's behavior depends on the class attribute cls_x and we want to set up this dependency during construction of B objects. Since it is not a simple operation, we want to wrap it in a class method, which the constructor will call. Example:
class B(A):
cls_x = 'B'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = B.cm()
Problem: cm as well as __init__ will always be doing the same things and their behavior must stay the same in each derived class. Thus, we would like to put them both in the base class and not define it in any of the derived classes. The only difference will be the caller of cm - either A or B (or any of B1, B2, each inheriting from A), whatever is being constructed. So what we'd like to have is something like this:
class A:
cls_x = 'A'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = ClassOfWhateverIsInstantiated.cm() #how to do this?
class B(A):
cls_x = 'B'
I feel like it's either something very simple I'm missing about Python's inheritance mechanics or the whole issue should be handled entirely differently.
This is different than this question as I do not want to override the class method, but move its implementation to the base class entirely.
Look at it this way: Your question is essentially "How do I get the class of an instance?". The answer to that question is to use the type function:
ClassOfWhateverIsInstantiated = type(self)
But you don't even need to do that, because classmethods can be called directly through an instance:
def __init__(self):
self.attr = self.cm() # just use `self`
This works because classmethods automatically look up the class of the instance for you. From the docs:
[A classmethod] can be called either on the class (such as C.f()) or on an instance
(such as C().f()). The instance is ignored except for its class.
For ClassOfWhateverIsInstantiated you can just use self:
class A:
cls_x = 'A'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = self.cm() # 'self' refers to B, if called from B
class B(A):
cls_x = 'B'
a = A()
print(a.cls_x) # = 'A'
print(A.cls_x) # = 'A'
b = B()
print(b.cls_x) # = 'B'
print(B.cls_x) # = 'B'
To understand this, just remember that class B is inheriting the methods of class A. So when __init__() is called during B's instantiation, it's called in the context of class B, to which self refers.