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 OverflowHow does python variable inheritance work? - Stack Overflow
Inherited class variable modification in Python - Stack Overflow
Confused about class variables, also with inheritance
inheritance - Inheriting from instance in Python - Stack Overflow
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
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.
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.
Currently, your code is invalid syntax as a digit cannot be at the very front of a variable name. However, you can use *args with __dict__:
class foo:
def __init__(self, *args):
self.__dict__ = dict(zip(['var{}'.format(i) for i in range(1, len(args)+1)], args))
f = foo(*range(15))
print(f.var1)
print(f.var14)
Output:
0
13
Use this as a template for your inheritance, emphasis on the super() method:
class Foo:
def __init__(self):
self.name = 'Foo'
class Bar(Foo):
def __init__(self):
super().__init__()
b = Bar()
b.name
# outputs 'Foo'
For your specific type of class (that takes an unknown number of initialization arguments, i.e. *args):
class Foo:
def __init__(self, *args):
self.name = 'Foo'
for i, arg in enumerate(args):
setattr(self, 'thing_' + str(i), arg)
class Bar(Foo):
def __init__(self, *args):
super().__init__(*args)
b = Bar('hello', 'world')
b.name
# outputs 'Foo'
b.thing_0
# outputs 'hello'
b.thing_1
# outputs 'world'
Now I would personally use the **kwargs over *args for specifying unique instance attributes:
class Foo:
def __init__(self, **kwargs):
self.name = 'Foo'
for att in kwargs:
setattr(self, att, kwargs[att])
class Bar(Foo):
def __init__(self, **kwargs):
super().__init__(**kwargs)
b = Bar(value = 4, area = 3.14)
b.name
# outputs 'Foo'
b.value
# outputs 4
b.area
# outputs 3.14
Any property of Dog will override a property inherited from Cat. You can re-define a value in Cat, but it won't matter because it has already been overridden by the child. For example:
class Cat:
age = 0 # Cat.age = 0
class Dog(Cat):
pass # Dog.age = Cat.age = 0
Dog.age=1 # Dog.age = 1, and Dog.age no longer points to Cat.age
Cat.age=2 # Cat.age = 2
print(Dog.age, Cat.age) # Dog.age is no longer Cat.age. They are completely different
Contrast that with this:
class Cat:
age = 0 # Cat.age = 0
class Dog(Cat):
pass # Dog.age = Cat.age = 0
Cat.age = 10 # Cat.age = 10
print(Dog.age, Cat.age) # Dog.age points to Cat.age, so Dog.age resolves to 10
Inheritance refers to defining a new class with little or no modification to an existing class. The new class is called derived (or child) class and the one from which it inherits is called the base (or parent) class. The class inheritance mechanism allows multiple base classes, a derived class can override any methods of its base class(es), and a method can call the method of a base class with the same name.
class Cat:
def __init__(self):
self.age = 2
self.sound = "meow"
class Dog(Cat):
def __init__(self):
super().__init__()
self.sound = "bark"
cat = Cat()
dog = Dog()
print(f"The cat's age is {cat.age}, and the dog's age is {dog.age}.")
print(f"Cats {cat.sound}, and dogs {dog.sound}.")
The cat's age is 2, and the dog's age is 2.
Cats meow, and dogs bark.
So, you can see the dog.age can inherit from class Cat. Notice the sound part, the method in the derived class overrides that in the base class. This is to say, we wrote the dog sound, it gets preference over the class Cat sound.
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)