183 lines
4.5 KiB
Markdown
183 lines
4.5 KiB
Markdown
![]() |
---
|
||
|
tags: [python, OOP]
|
||
|
---
|
||
|
|
||
|
# Classes in Python
|
||
|
|
||
|
## General points
|
||
|
|
||
|
- We don't need to use `new` when instantiating an instance of a class.
|
||
|
- All properties and methods must be defined in the constructor. This is in
|
||
|
contrast to JavaScript where the properties in the constructor are those we
|
||
|
want to initialise when the object is created and where there may be other
|
||
|
properties and methods that are used outside of the instantiation process.
|
||
|
- In contrast to TypeScript and other OOP languages it is not necessary to
|
||
|
declare the properties you wish to define in the constructor, outside of the
|
||
|
constructor. As long as they are defined in the constructor they are
|
||
|
accessible.
|
||
|
|
||
|
## Class properties
|
||
|
|
||
|
In contrast to other languages, you do not need to declare any properties you
|
||
|
wish to use in the class at the top before you can assign to them. This is true
|
||
|
whether you define them in the constructor or not.
|
||
|
|
||
|
Instead, you can create properties just by invoking `self.some_property_name` in
|
||
|
the course of your code and Python will create the variable implicitly.
|
||
|
|
||
|
For continuity with other languages you may however define them at the top of
|
||
|
the class if you wish.
|
||
|
|
||
|
## Basic syntax
|
||
|
|
||
|
```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 birthday(self):
|
||
|
print('Happy birthday you were', self.age)
|
||
|
self.age += 1
|
||
|
print('You are now', self.age)
|
||
|
|
||
|
p1 = Person('John', 36)
|
||
|
p2 = Person('Thomas', 34)
|
||
|
print(p1)
|
||
|
print(p2)
|
||
|
|
||
|
print(p1.name)
|
||
|
|
||
|
# 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
|
||
|
- `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
|
||
|
|
||
|
## Private, protected members and methods
|
||
|
|
||
|
As Python is not strictly typed the property accessors are not actually real and
|
||
|
won't throw errors if violated. However there is a syntax convention.
|
||
|
|
||
|
- Private
|
||
|
|
||
|
- `__self.property`
|
||
|
- `def __private method(self)...`
|
||
|
|
||
|
- Protected
|
||
|
|
||
|
- `_self.property`
|
||
|
- `def _protected method(self)...`
|
||
|
|
||
|
## 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](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](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
|
||
|
```
|