mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-08-15 11:14:24 +02:00
Python3/en: multiple inheritance (#2217)
* Add __name__ check to make testing easier * Update say to call print. Add more usage examples * Move Modules section before Classes Makes more sense for when explaining inheritance * Add multiple inheritance example * Add examples for multiple inheritance * Add instance check examples * Fix multiple inheritance example * Add note on the __name__ variable
This commit is contained in:
committed by
ven
parent
ec15a36de7
commit
e72c849556
@@ -601,95 +601,9 @@ list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7]
|
|||||||
[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
|
[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
|
||||||
[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
|
[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
|
||||||
|
|
||||||
####################################################
|
|
||||||
## 5. Classes
|
|
||||||
####################################################
|
|
||||||
|
|
||||||
|
|
||||||
# We use the "class" operator to get a class
|
|
||||||
class Human:
|
|
||||||
|
|
||||||
# A class attribute. It is shared by all instances of this class
|
|
||||||
species = "H. sapiens"
|
|
||||||
|
|
||||||
# Basic initializer, this is called when this class is instantiated.
|
|
||||||
# Note that the double leading and trailing underscores denote objects
|
|
||||||
# or attributes that are used by python but that live in user-controlled
|
|
||||||
# namespaces. Methods(or objects or attributes) like: __init__, __str__,
|
|
||||||
# __repr__ etc. are called magic methods (or sometimes called dunder methods)
|
|
||||||
# You should not invent such names on your own.
|
|
||||||
def __init__(self, name):
|
|
||||||
# Assign the argument to the instance's name attribute
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
# Initialize property
|
|
||||||
self.age = 0
|
|
||||||
|
|
||||||
# An instance method. All methods take "self" as the first argument
|
|
||||||
def say(self, msg):
|
|
||||||
return "{name}: {message}".format(name=self.name, message=msg)
|
|
||||||
|
|
||||||
# A class method is shared among all instances
|
|
||||||
# They are called with the calling class as the first argument
|
|
||||||
@classmethod
|
|
||||||
def get_species(cls):
|
|
||||||
return cls.species
|
|
||||||
|
|
||||||
# A static method is called without a class or instance reference
|
|
||||||
@staticmethod
|
|
||||||
def grunt():
|
|
||||||
return "*grunt*"
|
|
||||||
|
|
||||||
# A property is just like a getter.
|
|
||||||
# It turns the method age() into an read-only attribute
|
|
||||||
# of the same name.
|
|
||||||
@property
|
|
||||||
def age(self):
|
|
||||||
return self._age
|
|
||||||
|
|
||||||
# This allows the property to be set
|
|
||||||
@age.setter
|
|
||||||
def age(self, age):
|
|
||||||
self._age = age
|
|
||||||
|
|
||||||
# This allows the property to be deleted
|
|
||||||
@age.deleter
|
|
||||||
def age(self):
|
|
||||||
del self._age
|
|
||||||
|
|
||||||
|
|
||||||
# Instantiate a class
|
|
||||||
i = Human(name="Ian")
|
|
||||||
print(i.say("hi")) # prints out "Ian: hi"
|
|
||||||
|
|
||||||
j = Human("Joel")
|
|
||||||
print(j.say("hello")) # prints out "Joel: hello"
|
|
||||||
|
|
||||||
# Call our class method
|
|
||||||
i.get_species() # => "H. sapiens"
|
|
||||||
|
|
||||||
# Change the shared attribute
|
|
||||||
Human.species = "H. neanderthalensis"
|
|
||||||
i.get_species() # => "H. neanderthalensis"
|
|
||||||
j.get_species() # => "H. neanderthalensis"
|
|
||||||
|
|
||||||
# Call the static method
|
|
||||||
Human.grunt() # => "*grunt*"
|
|
||||||
|
|
||||||
# Update the property
|
|
||||||
i.age = 42
|
|
||||||
|
|
||||||
# Get the property
|
|
||||||
i.age # => 42
|
|
||||||
|
|
||||||
# Delete the property
|
|
||||||
del i.age
|
|
||||||
i.age # => raises an AttributeError
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
## 6. Modules
|
## 5. Modules
|
||||||
####################################################
|
####################################################
|
||||||
|
|
||||||
# You can import modules
|
# You can import modules
|
||||||
@@ -724,6 +638,189 @@ dir(math)
|
|||||||
# This happens because the local folder has priority
|
# This happens because the local folder has priority
|
||||||
# over Python's built-in libraries.
|
# over Python's built-in libraries.
|
||||||
|
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
## 6. Classes
|
||||||
|
####################################################
|
||||||
|
|
||||||
|
# We use the "class" operator to get a class
|
||||||
|
class Human:
|
||||||
|
|
||||||
|
# A class attribute. It is shared by all instances of this class
|
||||||
|
species = "H. sapiens"
|
||||||
|
|
||||||
|
# Basic initializer, this is called when this class is instantiated.
|
||||||
|
# Note that the double leading and trailing underscores denote objects
|
||||||
|
# or attributes that are used by python but that live in user-controlled
|
||||||
|
# namespaces. Methods(or objects or attributes) like: __init__, __str__,
|
||||||
|
# __repr__ etc. are called magic methods (or sometimes called dunder methods)
|
||||||
|
# You should not invent such names on your own.
|
||||||
|
def __init__(self, name):
|
||||||
|
# Assign the argument to the instance's name attribute
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
# Initialize property
|
||||||
|
self.age = 0
|
||||||
|
|
||||||
|
# An instance method. All methods take "self" as the first argument
|
||||||
|
def say(self, msg):
|
||||||
|
print ("{name}: {message}".format(name=self.name, message=msg))
|
||||||
|
|
||||||
|
# Another instance method
|
||||||
|
def sing(self):
|
||||||
|
return 'yo... yo... microphone check... one two... one two...'
|
||||||
|
|
||||||
|
# A class method is shared among all instances
|
||||||
|
# They are called with the calling class as the first argument
|
||||||
|
@classmethod
|
||||||
|
def get_species(cls):
|
||||||
|
return cls.species
|
||||||
|
|
||||||
|
# A static method is called without a class or instance reference
|
||||||
|
@staticmethod
|
||||||
|
def grunt():
|
||||||
|
return "*grunt*"
|
||||||
|
|
||||||
|
# A property is just like a getter.
|
||||||
|
# It turns the method age() into an read-only attribute
|
||||||
|
# of the same name.
|
||||||
|
@property
|
||||||
|
def age(self):
|
||||||
|
return self._age
|
||||||
|
|
||||||
|
# This allows the property to be set
|
||||||
|
@age.setter
|
||||||
|
def age(self, age):
|
||||||
|
self._age = age
|
||||||
|
|
||||||
|
# This allows the property to be deleted
|
||||||
|
@age.deleter
|
||||||
|
def age(self):
|
||||||
|
del self._age
|
||||||
|
|
||||||
|
|
||||||
|
# When a Python interpreter reads a source file it executes all its code.
|
||||||
|
# This __name__ check makes sure this code block is only executed when this
|
||||||
|
# module is the main program.
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Instantiate a class
|
||||||
|
i = Human(name="Ian")
|
||||||
|
i.say("hi") # "Ian: hi"
|
||||||
|
j = Human("Joel")
|
||||||
|
j.say("hello") # "Joel: hello"
|
||||||
|
# i and j are instances of type Human, or in other words: they are Human objects
|
||||||
|
|
||||||
|
# Call our class method
|
||||||
|
i.say(i.get_species()) # "Ian: H. sapiens"
|
||||||
|
# Change the shared attribute
|
||||||
|
Human.species = "H. neanderthalensis"
|
||||||
|
i.say(i.get_species()) # => "Ian: H. neanderthalensis"
|
||||||
|
j.say(j.get_species()) # => "Joel: H. neanderthalensis"
|
||||||
|
|
||||||
|
# Call the static method
|
||||||
|
print(Human.grunt()) # => "*grunt*"
|
||||||
|
print(i.grunt()) # => "*grunt*"
|
||||||
|
|
||||||
|
# Update the property for this instance
|
||||||
|
i.age = 42
|
||||||
|
# Get the property
|
||||||
|
i.say(i.age) # => 42
|
||||||
|
j.say(j.age) # => 0
|
||||||
|
# Delete the property
|
||||||
|
del i.age
|
||||||
|
# i.age # => this would raise an AttributeError
|
||||||
|
|
||||||
|
|
||||||
|
####################################################
|
||||||
|
## 6.1 Multiple Inheritance
|
||||||
|
####################################################
|
||||||
|
|
||||||
|
# Another class definition
|
||||||
|
class Bat:
|
||||||
|
|
||||||
|
species = 'Baty'
|
||||||
|
|
||||||
|
def __init__(self, can_fly=True):
|
||||||
|
self.fly = can_fly
|
||||||
|
|
||||||
|
# This class also has a say method
|
||||||
|
def say(self, msg):
|
||||||
|
msg = '... ... ...'
|
||||||
|
return msg
|
||||||
|
|
||||||
|
# And its own method as well
|
||||||
|
def sonar(self):
|
||||||
|
return '))) ... ((('
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
b = Bat()
|
||||||
|
print(b.say('hello'))
|
||||||
|
print(b.fly)
|
||||||
|
|
||||||
|
|
||||||
|
# from "filename-without-extension" import "function-or-class"
|
||||||
|
from human import Human
|
||||||
|
from bat import Bat
|
||||||
|
|
||||||
|
# Batman inherits from both Human and Bat
|
||||||
|
class Batman(Human, Bat):
|
||||||
|
|
||||||
|
# Batman has its own value for the species class attribute
|
||||||
|
species = 'Superhero'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# Typically to inherit attributes you have to call super:
|
||||||
|
#super(Batman, self).__init__(*args, **kwargs)
|
||||||
|
# However we are dealing with multiple inheritance here, and super()
|
||||||
|
# only works with the next base class in the MRO list.
|
||||||
|
# So instead we explicitly call __init__ for all ancestors.
|
||||||
|
# The use of *args and **kwargs allows for a clean way to pass arguments,
|
||||||
|
# with each parent "peeling a layer of the onion".
|
||||||
|
Human.__init__(self, 'anonymous', *args, **kwargs)
|
||||||
|
Bat.__init__(self, *args, can_fly=False, **kwargs)
|
||||||
|
# override the value for the name attribute
|
||||||
|
self.name = 'Sad Affleck'
|
||||||
|
|
||||||
|
def sing(self):
|
||||||
|
return 'nan nan nan nan nan batman!'
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sup = Batman()
|
||||||
|
|
||||||
|
# Instance type checks
|
||||||
|
if isinstance(sup, Human):
|
||||||
|
print('I am human')
|
||||||
|
if isinstance(sup, Bat):
|
||||||
|
print('I am bat')
|
||||||
|
if type(sup) is Batman:
|
||||||
|
print('I am Batman')
|
||||||
|
|
||||||
|
# Get the Method Resolution search Order used by both getattr() and super().
|
||||||
|
# This attribute is dynamic and can be updated
|
||||||
|
print(Batman.__mro__) # => (<class '__main__.Batman'>, <class 'human.Human'>, <class 'bat.Bat'>, <class 'object'>)
|
||||||
|
|
||||||
|
# Calls parent method but uses its own class attribute
|
||||||
|
print(sup.get_species()) # => Superhero
|
||||||
|
|
||||||
|
# Calls overloaded method
|
||||||
|
print(sup.sing()) # => nan nan nan nan nan batman!
|
||||||
|
|
||||||
|
# Calls method from Human, because inheritance order matters
|
||||||
|
sup.say('I agree') # => Sad Affleck: I agree
|
||||||
|
|
||||||
|
# Call method that exists only in 2nd ancestor
|
||||||
|
print(sup.sonar()) # => ))) ... (((
|
||||||
|
|
||||||
|
# Inherited class attribute
|
||||||
|
sup.age = 100
|
||||||
|
print(sup.age)
|
||||||
|
|
||||||
|
# Inherited attribute from 2nd ancestor whose default value was overriden
|
||||||
|
print('Can I fly? ' + str(sup.fly))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
## 7. Advanced
|
## 7. Advanced
|
||||||
####################################################
|
####################################################
|
||||||
|
Reference in New Issue
Block a user