diff --git a/Programming_Languages/Python/Syntax/Class_inheritance_in_Python.md b/Programming_Languages/Python/Syntax/Class_inheritance_in_Python.md new file mode 100644 index 0000000..f7a79fd --- /dev/null +++ b/Programming_Languages/Python/Syntax/Class_inheritance_in_Python.md @@ -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. diff --git a/Programming_Languages/Python/Syntax/Classes_in_Python.md b/Programming_Languages/Python/Syntax/Classes_in_Python.md index 94971a5..9d67aa6 100644 --- a/Programming_Languages/Python/Syntax/Classes_in_Python.md +++ b/Programming_Languages/Python/Syntax/Classes_in_Python.md @@ -27,24 +27,112 @@ class Person: self.age += 1 print('You are now', self.age) - p1 = Person('John', 36) p2 = Person('Thomas', 34) print(p1) print(p2) print(p1.name) -# <__main__.Person object at 0x102e75510> -# <__main__.Person object at 0x102e75511> + # John ``` Key points to note: - 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 - 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 -## 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 +``` diff --git a/_meta/Topic_Log.md b/_meta/Topic_Log.md index 6c8915f..1a8a824 100644 --- a/_meta/Topic_Log.md +++ b/_meta/Topic_Log.md @@ -19,6 +19,7 @@ - Modules - Error handling - Testing + - I/O ## Bash @@ -59,6 +60,8 @@ ## NodeJS - 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