You should call __init__ from the parent class:
class Person(object):
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
class Teacher(Person):
def __init__(self, name, occupation, subject):
Person.__init__(self, name, occupation)
self.subject = subject
Answer from Daniel on Stack OverflowCan child classes inherit instance variables from their parent class in Python? - Stack Overflow
Inherited class variable modification in Python - Stack Overflow
Python inherit variables from parent class - Stack Overflow
Confused about class variables, also with inheritance
Assuming you want to have a separate list in the subclass, not modify the parent class's list (which seems pointless since you could just modify it in place, or put the expected values there to begin with):
class Child(Parent):
foobar = Parent.foobar + ['world']
Note that this works independently of inheritance, which is probably a good thing.
You should not use mutable values in your class variables. Set such values on the instance instead, using the __init__() instance initializer:
class Parent(object):
def __init__(self):
self.foobar = ['Hello']
class Child(Parent):
def __init__(self):
super(Child, self).__init__()
self.foobar.append('world')
Otherwise what happens in that the foobar list is shared among not only the instances, but with the subclasses as well.
In any case, you'll have to avoid modifying mutables of parent classes even if you do desire to share state among instances through a mutable class variable; only assignment to a name would create a new variable:
class Parent(object):
foobar = ['Hello']
class Child(Parent):
foobar = Parent.foobar + ['world']
where a new foobar variable is created for the Child class. By using assignment, you've created a new list instance and the Parent.foobar mutable is unaffected.
Do take care with nested mutables in such cases; use the copy module to create deep copies if necessary.
What you ask does not make sense:
class Parent:
def __init__(self, eye_color, length):
self.eye_color = str(eye_color)
self.length = length
class Child(Parent):
def __init__(self, gender):
super().__init__(eye_color, length)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men")
print(x.length, x.eye_color)
print(y.gender, x.length)
In child, the parameters eye_color and length come from nowhere.
rassar example is good if you want to reuse a parent object.
You can also do the following:
class Parent:
# def __init__(self, eye_color=(default value here), length=(default value here)):
def __init__(self, eye_color="", length=0):
self.eye_color = str(eye_color)
self.length = length
OR
class Parent:
def __init__(self, eye_color="", length=0):
self.eye_color = str(eye_color)
self.length = length
class Child(Parent):
def __init__(self, gender, *args, **kwargs):
super().__init__(*args, **kwargs)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men") # Work with first example of Parent
y = Child("Men", eye_color="Blue", length=2) # Work with first
y = Child("Men", "Blue", 2) # Work with second example
print(x.length, x.eye_color)
print(y.gender, y.length)
You could try passing a Parent instance to the Child initializer...That's probably the closest you'll get.
class Parent:
def __init__(self, eye_color, length):
self.eye_color = str(eye_color)
self.length = length
class Child(Parent):
def __init__(self, gender, parent):
super().__init__(parent.eye_color, parent.length)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men", x)
print(x.length, x.eye_color)
print(y.gender, x.length)
Another thing you could do is hold a last_parent variable:
global last_parent
class Parent:
def __init__(self, eye_color, length):
self.eye_color = str(eye_color)
self.length = length
last_parent = self
class Child(Parent):
def __init__(self, gender):
super().__init__(last_parent.eye_color, last_parent.length)
self.gender = str(gender)
x = Parent("Blue", 2)
y = Child("Men")
print(x.length, x.eye_color)
print(y.gender, x.length)
I'm finding class variables super confusing. I thought they were just like static variables in C++ (which instances can't own), but it seems they have quite different behavior.
Basic Class variable behavior - is this correct?
class Foo: x: int
-
if you set
Foo.x, it overrides the value of.xfor all instances of Foo, but -
if you set
.xon an instance ofFoo, it only changes.xon that instance.
edit: actually this can't be the full story, because sometimes changing Foo.x doesn't change the instance's .x??
Class variables + inheritance, what is going on?
class Parent: x: int class Child(Parent): pass Parent.x = 1 print(Child.x) # = 1. ok so child inherits parent class variable Child.x = 2 print(Parent.x) # = 1. ok, so child cannot set parent class variable Parent.x = 3 print(Child.x) # = 2. hol' up, now child doesn't inherit from parent anymore?
Also, if multiple classes inherit from Parent, if I set Child1.x does it affect the other children? How are instances affected too?
Class variables without declaration works too...?
What's the point of defining these variables in the class body if you don't need to?
class Foo: pass Foo.x = 3
I feel like there's some kind of mental model for class variables I'm just not understanding. Is there any easy way to think about them? Also is there any other weird behavior I should know?
I find this (encapsulation) to be the cleanest way:
class Child(object):
def __init__(self):
self.obj = Parent()
def __getattr__(self, attr):
return getattr(self.obj, attr)
This way you can use all Parent's method and your own without running into the problems of inheritance.
OK, so I didn't realize that you where happy with a static copy of the arguments until I was already halfway done with my solution. But I decided not to waste it, so here it is anyway. The difference from the other solutions is that it will actually get the attributes from the parent even if they updated.
_marker = object()
class Parent(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
class Child(Parent):
_inherited = ['x', 'y', 'z']
def __init__(self, parent):
self._parent = parent
self.a = "not got from dad"
def __getattr__(self, name, default=_marker):
if name in self._inherited:
# Get it from papa:
try:
return getattr(self._parent, name)
except AttributeError:
if default is _marker:
raise
return default
if name not in self.__dict__:
raise AttributeError(name)
return self.__dict__[name]
Now if we do this:
>>> A = Parent('gotten', 'from', 'dad')
>>> B = Child(A)
>>> print "a, b and c is", B.x, B.y, B.z
a, b and c is gotten from dad
>>> print "But x is", B.a
But x is not got from dad
>>> A.x = "updated!"
>>> print "And the child also gets", B.x
And the child also gets updated!
>>> print B.doesnotexist
Traceback (most recent call last):
File "acq.py", line 44, in <module>
print B.doesnotexist
File "acq.py", line 32, in __getattr__
raise AttributeError(name)
AttributeError: doesnotexist
For a more generic version of this, look at the http://pypi.python.org/pypi/Acquisition package. It is in fact, in some cases a bloody need solution.
You need to call the constructor of the parent classes manually - Here, self.text is initialize in Parent constructor which is never called:
class Child1(Parent):
def __init__ (self):
super(Child1, self).__init__ ()
# or Parent.__init__ (self)
self.x = 'x'
Since python 3.6, we can now use the __init_subclass__ function, which is called automatically before __init__ of the Child.
class Parent:
def __init__(self):
self.text = 'parent'
def __init_subclass__(self):
Parent.__init__(self)
def getText(self):
print(self.text)
class Child1(Parent): pass
class Child2(Parent): pass
classes = [Parent(), Child1(), Child2()]
for item in classes:
item.getText()
output
parent
parent
parent
If you use your Parent class more as a "interface", here is another example.
class Animal():
def __init_subclass__(self, sound):
self.sound = sound
def make_sound(self):
print(self.sound)
class Cat(Animal, sound='meow'): pass
class Dog(Animal, sound='woof'): pass
animals = [Cat(), Dog()]
for animal in animals:
animal.make_sound()
output
meow
woof
You're mixing up class and instance attributes.
print self._haircolor
You want the instance attribute, not the class attribute, so you should use self._haircolor.
Also, you really should use super in the __init__ in case you decide to change your inheritance to Father or something.
class Child(Mother):
def __init__(self):
super(Child, self).__init__()
def print_haircolor(self):
print self._haircolor
You don't need to do anything special. Just accessing self.rep1 from within a method of Second will give you the value. Of course, the value still needs to be set in that specific object, so if you have ob = Second(), you first have to call ob.one().
You could try something like:
def Second(First):
def two(self):
self.one()
self.rep2 = 'Rep2'
print(self.rep1, self.rep2) # this will access the value set by one()
What happens is that rep1 won't exist at least you first the method one().
You can do this:
class First:
def __init__(self):
self.one()
def one(self):
self.rep1 = 'Rep1.\n'
class Second(First):
def two(self):
self.rep2 = 'Rep2'
self.rep1 = self.rep1
print('From Second: %sFrom First: %s' % (self.rep2, self.rep1))
You can simply access to rep1 as if it were defined in the Second class because of inheritance.
You need to do:
class A:
def __init__(self):
self.mylist=[]
That way self.mylist is an instance variable. If you define it outside of a method it is a class variable and so shared between all instances.
In B if you define a constructor you'll have to explicitly call A's constructor:
class B(A):
def __init__(self):
A.__init__(self)
This is explained (not very clearly) in the Python tutorial.
This code creates a shared mylist among all instances of A (or subclasses)
class A():
mylist=[]
What you want to do is:
class A():
def __init__(self):
self.mylist=[]
What you've probably seen is people who do:
class A():
somevariable = a
def doit(self):
self.somevariable = 5
This works because it creates a new "somevariable" attribute because you are doing an assignment. Before that all A instances share the same copy of somevariable. As long as you don't change the copy that is fine. When the variable is assigned to, then it gets replaced rather then modified. So that technique is only really safe when the values in question are immutable (i.e. you can't change them, you can only replace them) However, I think that's a really bad idea and you should always assign all variables in init
You have to call the __init__() method of the super() object. Something like this:
class BaselineModels:
def __init__(self):
self.logpath = './log/models/'
self.mpath = './models/'
class ALS(BaselineModels):
def __init__(self):
super().__init__()
self.model_name = 'als'
def run(self):
df = self.csv_to_df()
als = ALS()
als.mpath
# returns:
'./models/'
You can follow this method also.
class BaselineModels:
def __init__(self):
self.logpath = './log/models/'
self.mpath = './models/'
class ALS(BaselineModels):
def __init__(self):
super(ALS, self).__init__()
self.model_name = 'als'
def run(self):
df = self.csv_to_df()
als = ALS()
als.mpath
# returns:
'./models/'
Python's method resolution order works from Left to Right. It will only call the init method of the first class(A in your case). This will give you the desired result-
class A():
def __init__(self):
super().__init__()
self.x = 1
# parent class B
class B():
def __init__(self):
super().__init__()
self.y = 2
# parent class C
class C():
def __init__(self):
self.z = 3
# target class D
class D(A, B, C):
def __init__(self):
super().__init__()
d = D()
print(vars(d))
In Python, when a class inherits from multiple parent classes, it is called multiple inheritance. In the given code, classes A, B, and C are individual classes without any direct parent classes, but they are used as base classes for the target class D. Even though these classes don't have explicit parent classes, they still require super().init() calls in their init methods because they participate in the method resolution order (MRO) used by Python to determine the order in which the init methods of the parent classes are called.
The Method Resolution Order (MRO) is a specific order in which Python searches for methods and attributes in a class hierarchy. It is determined using the C3 linearization algorithm, which helps to resolve potential ambiguities and conflicts that may arise in multiple inheritance scenarios.
In your example, when you create an instance of class D, it inherits from classes A, B, and C. The MRO is determined in a left-to-right, depth-first manner, so it follows the order of the base classes:
MRO(D) = [D, A, B, C]
Let's break down why the super().init() calls are necessary in each class:
Class A: It has no parent classes, but it's still included in the MRO because it is part of the inheritance chain for class D. The super().init() call in class A will call the init method of class B (the next class in the MRO), which in turn will call the init method of class C. Although class A doesn't have any initialization logic of its own, it is essential to call super().init() to maintain the proper MRO and ensure that the initialization logic of the other classes is executed.
Class B: Similarly to class A, class B doesn't have any direct parent classes but participates in the MRO as part of the inheritance chain for class D. The super().init() call in class B will call the init method of class C, which is the next class in the MRO.
Class C: Class C is the last class in the MRO for class D, and it initializes the attribute z with the value 3.
Class D: Finally, when you create an instance of class D, its init method will be called, and it calls super().init() to trigger the initialization process for classes A, B, and C in the correct order based on the MRO.
As a result, when you create an instance of class D, all the init methods of classes A, B, and C are executed in the correct order, and you end up with an object that has attributes x, y, and z, each initialized with their respective values.
To summarize, even though classes A and B don't have direct parent classes, they are part of the multiple inheritance chain for class D, and the super().init() calls are needed to ensure that the proper MRO is followed, and the initialization logic of all base classes is executed correctly.
It must be self.x, not just x:
class A(object):
def __init__(self):
self.x = 0
Just a quick note - even from other methods of A would be the x not accessible:
class A(object):
def __init__(self):
x = 0
def foo(self):
print(self.x) # <- will not work
print(x) # <- will utimately not work
You need to set it as self.x = 0 instead of x = 0 - otherwise it's just a local variable.
If you cannot modify A, what you are trying to do is impossible - there is absolutely no way to access that value, not even with black magic (if your method was called by that method, you could probably do nasty things with the stack to get its value)