mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 09:41:36 +00: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:
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]
|
||||
[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
|
||||
@ -724,6 +638,189 @@ dir(math)
|
||||
# This happens because the local folder has priority
|
||||
# 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
|
||||
####################################################
|
||||
|
Loading…
Reference in New Issue
Block a user