Autosave: 2023-02-17 12:05:32
This commit is contained in:
parent
7afcd00f8e
commit
31938fa75c
3 changed files with 164 additions and 5 deletions
|
@ -0,0 +1,68 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Programming Languages
|
||||||
|
tags: [python, OOP]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Class inheritance in Python
|
||||||
|
|
||||||
|
We distinguish the **parent/source/superclass** class and the **subclass** that **extends** it.
|
||||||
|
|
||||||
|
A subclass can have more than one parent class that it extends, but this is atypical.
|
||||||
|
|
||||||
|
> The subclass will inherit all attributes and methods of the superclass unless it overrides them.
|
||||||
|
|
||||||
|
In addition to overriding the methods of the parent we can extend them in the child. This is a bit like using an abstract.
|
||||||
|
|
||||||
|
## Example of class inheritance
|
||||||
|
|
||||||
|
```py
|
||||||
|
|
||||||
|
class Person:
|
||||||
|
""" Our superclass
|
||||||
|
"""
|
||||||
|
def __init__(self, name, age):
|
||||||
|
self.name = name
|
||||||
|
self.age = age
|
||||||
|
|
||||||
|
def birthday(self):
|
||||||
|
print('Happy birthday you were', self.age)
|
||||||
|
self.age += 1
|
||||||
|
print('You are now', self.age)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name + ' is ' + str(self.age)
|
||||||
|
|
||||||
|
|
||||||
|
class Employee(Person):
|
||||||
|
""" Our subclass that extends `Person`
|
||||||
|
"""
|
||||||
|
def __init__(self, name, age, id):
|
||||||
|
super().__init__(name, age)
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
def calculate_pay(self, hours_worked):
|
||||||
|
rate_of_pay = 7.50
|
||||||
|
if self.age >= 21:
|
||||||
|
rate_of_pay += 2.50
|
||||||
|
return hours_worked * rate_of_pay
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return super().__str__() + ' - id(' + str(self.id) + ')'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key points
|
||||||
|
|
||||||
|
- We pass the name of the parent class to the child class as a parameter
|
||||||
|
- We must include all of the parent class's attributes in the constructor of the subclass
|
||||||
|
- We must use a special `super().__init__(..,...)` method to enact the extension of the parent. This method references the `__init__` class in the parent.
|
||||||
|
|
||||||
|
## Protected/private methods and attributes
|
||||||
|
|
||||||
|
> Protected methods and attributes are private to the class but can be accessed from any subclass
|
||||||
|
|
||||||
|
> Private methods cannot be accessed from anywhere outside of the class
|
||||||
|
|
||||||
|
We declare private methods and attributes with a double underscore (`__`). We declare protected methods and attributes with a single underscore (`_`).
|
||||||
|
|
||||||
|
This is **convention**, there are not actually private and protected attributes or properties.
|
|
@ -27,24 +27,112 @@ class Person:
|
||||||
self.age += 1
|
self.age += 1
|
||||||
print('You are now', self.age)
|
print('You are now', self.age)
|
||||||
|
|
||||||
|
|
||||||
p1 = Person('John', 36)
|
p1 = Person('John', 36)
|
||||||
p2 = Person('Thomas', 34)
|
p2 = Person('Thomas', 34)
|
||||||
print(p1)
|
print(p1)
|
||||||
print(p2)
|
print(p2)
|
||||||
|
|
||||||
print(p1.name)
|
print(p1.name)
|
||||||
# <__main__.Person object at 0x102e75510>
|
|
||||||
# <__main__.Person object at 0x102e75511>
|
|
||||||
# John
|
# John
|
||||||
```
|
```
|
||||||
|
|
||||||
Key points to note:
|
Key points to note:
|
||||||
|
|
||||||
- The `__init__` method is the constructor function and must exist on every class to define the properties of the class
|
- The `__init__` method is the constructor function and must exist on every class to define the properties of the class
|
||||||
- Every object that the class instantiates is a unique intem in memory as indicated by the hexadecimal log.
|
|
||||||
- `self` is a reference to the class itself and the object it will create, akin to `this` in other languages
|
- `self` is a reference to the class itself and the object it will create, akin to `this` in other languages
|
||||||
- You must pass `self` as a parameter to every method (this is a difference from JS)
|
- You must pass `self` as a parameter to every method (this is a difference from JS)
|
||||||
- As with functions, we can use docstrings to document the class. What you write here will show up in Intellisense etc
|
- As with functions, we can use docstrings to document the class. What you write here will show up in Intellisense etc
|
||||||
|
|
||||||
## The `str` method
|
## More complex class
|
||||||
|
|
||||||
|
```py
|
||||||
|
class Person:
|
||||||
|
""" An example class to hold a persons name and age"""
|
||||||
|
|
||||||
|
def __init__(self, name, age):
|
||||||
|
self.name = name
|
||||||
|
self.age = age
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name + ' is ' + str(self.age)
|
||||||
|
|
||||||
|
def birthday(self):
|
||||||
|
print ('Happy birthday you were', self.age)
|
||||||
|
self.age += 1
|
||||||
|
print('You are now', self.age)
|
||||||
|
|
||||||
|
def calculate_pay(self, hours_worked):
|
||||||
|
rate_of_pay = 7.50
|
||||||
|
if self.age >= 21:
|
||||||
|
rate_of_pay += 2.50
|
||||||
|
return hours_worked * rate_of_pay
|
||||||
|
|
||||||
|
def is_teenager(self):
|
||||||
|
return self.age < 20
|
||||||
|
```
|
||||||
|
|
||||||
|
## Object references
|
||||||
|
|
||||||
|
When you log a class you get a reference to its hexadecimal [memory](/Computer_Architecture/Memory/Memory.md) reference.
|
||||||
|
|
||||||
|
```py
|
||||||
|
p1 = Person('John', 36)
|
||||||
|
p2 = Person('Thomas', 34)
|
||||||
|
|
||||||
|
print(p1)
|
||||||
|
print(p2)
|
||||||
|
|
||||||
|
# <__main__.Person object at 0x102e75510>
|
||||||
|
# <__main__.Person object at 0x102e75511>
|
||||||
|
```
|
||||||
|
|
||||||
|
This shows each object is unique. You can also generate a specific ID with the `id()` method:
|
||||||
|
|
||||||
|
```py
|
||||||
|
print(id(p1))
|
||||||
|
print(id(p2))
|
||||||
|
|
||||||
|
# 4379088272
|
||||||
|
# 4379088656
|
||||||
|
```
|
||||||
|
|
||||||
|
## Copying objects
|
||||||
|
|
||||||
|
The same principle that applies to [copying functions](/Programming_Languages/Python/Syntax/Functions_in_Python.md) applies to copying objects created through classes: redeclaration results in a duplicate entity. Thus changes to the duplicate will affect the original.
|
||||||
|
|
||||||
|
This becomes obvious when you use `id()` but otherwise might not be apparent. To copy you should therefore declare a new instance of the class.
|
||||||
|
|
||||||
|
### The `str` method
|
||||||
|
|
||||||
|
The memory reference isn't very helpful for viewing the data contents. To get around this we can use the builtin `__string__` method which automatically logs whatever properties you put in there:
|
||||||
|
|
||||||
|
```py
|
||||||
|
class Person:
|
||||||
|
""" An example class to hold a persons name and age"""
|
||||||
|
|
||||||
|
def __init__(self, name, age):
|
||||||
|
self.name = name
|
||||||
|
self.age = age
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name + ' is ' + str(self.age)
|
||||||
|
|
||||||
|
p3 = Person('Thomas', 34)
|
||||||
|
print(p3)
|
||||||
|
# Thomas is 34
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deleting objects
|
||||||
|
|
||||||
|
You might want to delete an object reference because:
|
||||||
|
|
||||||
|
- the variable referencing the object goes out of scope
|
||||||
|
- the variable is set to `None`
|
||||||
|
|
||||||
|
After the `del` statement is applied to a variable that holds an object, the object will no longer be available and any attempt to reference it will result in an error.
|
||||||
|
|
||||||
|
```py
|
||||||
|
p1 = Person('J-Man', 76)
|
||||||
|
del p1
|
||||||
|
```
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
- Modules
|
- Modules
|
||||||
- Error handling
|
- Error handling
|
||||||
- Testing
|
- Testing
|
||||||
|
- I/O
|
||||||
|
|
||||||
## Bash
|
## Bash
|
||||||
|
|
||||||
|
@ -59,6 +60,8 @@
|
||||||
## NodeJS
|
## NodeJS
|
||||||
|
|
||||||
- Build examples of read stream and write stream
|
- Build examples of read stream and write stream
|
||||||
|
- Can you override parent class methods in JS subclass?
|
||||||
|
- If not in JS, can you do this in TS?
|
||||||
|
|
||||||
## Git
|
## Git
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue