Skip to content

Commit 0830deb

Browse files
committed
Check m09 classes
1 parent 38a9d47 commit 0830deb

6 files changed

Lines changed: 133 additions & 53 deletions

File tree

slides/content/m09_classes.md

Lines changed: 91 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
# 🐍 Classes
44
<!-- .element: class="headline" -->
55

6-
Python is object-oriented as well, of course, though, it follows a more lean approach towards classes.
7-
Let's have a look.
6+
Python is object-oriented, but follows a more lean approach towards classes.
87

98
<div class="sidebyside">
109

1110
```java
12-
// ./java/M09_PassengersProgram.java#L3-L38
11+
// ./java/M09_PassengersProgram.java#L3-L40
1312

1413
class Passenger {
1514

@@ -21,14 +20,16 @@ class Passenger {
2120
this.lastName = lastName;
2221
}
2322

24-
void print() {
23+
void display() {
2524
System.out.printf("%s %s %n", firstName, lastName);
2625
}
2726

2827
static Passenger fromInput() {
2928
Scanner scanner = new Scanner(System.in);
3029

30+
System.out.print("Enter first name: ");
3131
String firstName = scanner.nextLine();
32+
System.out.print("Enter last name: ");
3233
String lastName = scanner.nextLine();
3334

3435
scanner.close();
@@ -43,13 +44,13 @@ class PassengersProgram {
4344
Passenger lisa = new Passenger("Lisa", "Ha");
4445
Passenger user = Passenger.fromInput();
4546

46-
lisa.print();
47-
user.print();
47+
lisa.display();
48+
user.display();
4849
}
4950
}
5051
```
5152

52-
```py
53+
```py [|4-6|8-9|11-16|20-24|19|]
5354
# ./python/m09_passengers_program.py
5455

5556
class Passenger:
@@ -62,16 +63,18 @@ class Passenger:
6263

6364
@staticmethod
6465
def from_input():
65-
first_name = input()
66-
last_name = input()
66+
first_name = input("Enter first name: ")
67+
last_name = input("Enter last name: ")
6768

6869
return Passenger(first_name, last_name)
6970

70-
lisa = Passenger("Lisa", "Ha")
71-
# user = Passenger.from_input()
7271

73-
lisa.display()
74-
# user.display()
72+
if __name__ == "__main__":
73+
lisa = Passenger("Lisa", "Ha")
74+
user = Passenger.from_input()
75+
76+
lisa.display()
77+
user.display()
7578

7679
```
7780

@@ -81,22 +84,32 @@ lisa.display()
8184

8285
### What do we notice here?
8386

84-
- Python only ever has one constructor that is called `__init__` and must have the `self` parameter
85-
- Python has no method overloading
86-
- We don't explicitly define the class properties `first_name` and `last_name`
87-
- You create them on-the-fly in the constructor
88-
- What makes a function a method in Python is only governed by the explicit `self` parameter
89-
- And you always have to use `self.` if you want to access class properties
90-
- A static method in Python needs the `@staticmethod` annotation and omits the `self` parameter
91-
- A static method just means that it won't access any class properties
92-
- Creating a new object works similar in Python, but we omit the `new` keyword
93-
- There are no access modifiers and there also is no `final` in Python
87+
#### Constructors
9488

95-
---
89+
- There is only one **constructor** that is called `__init__` with a mandatory `self` parameter
90+
- Python does not support constructor overloading or **method overloading**
91+
- We don't explicitly define the **class properties** `first_name` and `last_name`,
92+
but you create them on-the-fly in the constructor or elsewhere
93+
94+
#### Functions and methods
95+
96+
- What makes a function a method is only governed by the explicit `self` parameter
97+
- You must always use `self.` if you want to access class properties
98+
- There are no access modifiers and there is also no `final` in Python
99+
100+
#### Static methods
101+
102+
- A **static method** needs the `@staticmethod` annotation and omits the `self` parameter
103+
- A static method just means that it won't access any class properties
96104

97-
## Interfaces
105+
#### Instantiation
98106

99-
What you might know from interfaces in Java can be achieved a little bit different with a dynamically-typed language like Python.
107+
- Creating a new object works similar, but you omit the `new` keyword
108+
- The `main` method in Python is actually a condition - we will learn more in the next modules
109+
110+
---
111+
112+
## Informal Interfaces
100113

101114
<div class="sidebyside">
102115

@@ -138,10 +151,7 @@ class Square implements Shape {
138151
class ShapesProgram {
139152

140153
public static void main(String[] args) {
141-
Square square = new Square(10);
142-
Circle circle = new Circle(5);
143-
144-
Shape[] shapes = {square, circle};
154+
Shape[] shapes = { new Circle(5), new Square(10) };
145155
for (Shape shape : shapes) {
146156
System.out.println(shape.area());
147157
}
@@ -150,23 +160,30 @@ class ShapesProgram {
150160

151161
```
152162

153-
```py
163+
```py [|3-5|8-13|16-21|24-26|]
154164
# ./python/m09_shapes_program.py
155165

156-
class Circle:
166+
class Shape:
167+
def area(self):
168+
pass
169+
170+
171+
class Circle(Shape):
157172
def __init__(self, radius):
158173
self.radius = radius
159174

160175
def area(self):
161176
return 3.14159 * self.radius * self.radius
162177

163-
class Square:
178+
179+
class Square(Shape):
164180
def __init__(self, length):
165181
self.length = length
166182

167183
def area(self):
168184
return self.length * self.length
169185

186+
170187
shapes = [Circle(5), Square(10)]
171188
for shape in shapes:
172189
print(shape.area())
@@ -175,11 +192,47 @@ for shape in shapes:
175192

176193
</div>
177194

195+
### What do we notice here?
196+
197+
- There is no `interface` type in Python, instead we use a normal `class` and inhert from it
198+
- Methods are overridden without an explicit annotation - they are always replaced
199+
- No type checks are enforced by Python, try removing `Shape` or renaming the `area()` method ...
200+
178201
---
179202

180-
### What do we notice here?
203+
## Duck-Typing
204+
205+
Since there is NO type-checking at compile-time, we may also solely rely on [**duck-typing**](https://docs.python.org/3/glossary.html#term-duck-typing).
206+
An `AttributeError` is thrown at runtime, if the method you are calling wouldn't exist. *
207+
208+
```py [|3-16|19-21|21|]
209+
# ./python/m09_shapes_duck_typing.py
210+
211+
class Circle:
212+
def __init__(self, radius):
213+
self.radius = radius
214+
215+
def area(self):
216+
return 3.14159 * self.radius * self.radius
217+
218+
219+
class Square:
220+
def __init__(self, length):
221+
self.length = length
222+
223+
def area(self):
224+
return self.length * self.length
225+
226+
227+
shapes = [Circle(5), Square(10)]
228+
for shape in shapes:
229+
print(shape.area())
230+
231+
```
232+
233+
### But, how can I have a "real" interfaces and inheritance in Python?
234+
235+
- Use abstract classes via the [**`abc` module**](https://docs.python.org/3/library/abc.html)
236+
- Learn more about formal interfaces at [realpython.com/python-interface](https://realpython.com/python-interface/)
181237

182-
- Because there is no hard type checking at compile-time, we can rely on duck-typing here
183-
- However, for a better code structures, Python offers the following
184-
- abstract classes (see https://docs.python.org/3/library/abc.html)
185-
- protocols (see https://www.python.org/dev/peps/pep-0544/)
238+
<small>* Look into [**type hints**](https://docs.python.org/3/library/typing.html) to have better type-checking at runtime and even before you run your code.</small>

snippets/java/M09_PassengersProgram.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@ class Passenger {
1010
this.lastName = lastName;
1111
}
1212

13-
void print() {
13+
void display() {
1414
System.out.printf("%s %s %n", firstName, lastName);
1515
}
1616

1717
static Passenger fromInput() {
1818
Scanner scanner = new Scanner(System.in);
1919

20+
System.out.print("Enter first name: ");
2021
String firstName = scanner.nextLine();
22+
System.out.print("Enter last name: ");
2123
String lastName = scanner.nextLine();
2224

2325
scanner.close();
@@ -32,7 +34,7 @@ public static void main(String[] args) {
3234
Passenger lisa = new Passenger("Lisa", "Ha");
3335
Passenger user = Passenger.fromInput();
3436

35-
lisa.print();
36-
user.print();
37+
lisa.display();
38+
user.display();
3739
}
3840
}

snippets/java/M09_ShapesProgram.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,7 @@ public double area() {
3333
class ShapesProgram {
3434

3535
public static void main(String[] args) {
36-
Square square = new Square(10);
37-
Circle circle = new Circle(5);
38-
39-
Shape[] shapes = {square, circle};
36+
Shape[] shapes = { new Circle(5), new Square(10) };
4037
for (Shape shape : shapes) {
4138
System.out.println(shape.area());
4239
}

snippets/python/m09_passengers_program.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ def display(self):
88

99
@staticmethod
1010
def from_input():
11-
first_name = input()
12-
last_name = input()
11+
first_name = input("Enter first name: ")
12+
last_name = input("Enter last name: ")
1313

1414
return Passenger(first_name, last_name)
1515

16-
lisa = Passenger("Lisa", "Ha")
17-
# user = Passenger.from_input()
1816

19-
lisa.display()
20-
# user.display()
17+
if __name__ == "__main__":
18+
lisa = Passenger("Lisa", "Ha")
19+
user = Passenger.from_input()
20+
21+
lisa.display()
22+
user.display()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class Circle:
2+
def __init__(self, radius):
3+
self.radius = radius
4+
5+
def area(self):
6+
return 3.14159 * self.radius * self.radius
7+
8+
9+
class Square:
10+
def __init__(self, length):
11+
self.length = length
12+
13+
def area(self):
14+
return self.length * self.length
15+
16+
17+
shapes = [Circle(5), Square(10)]
18+
for shape in shapes:
19+
print(shape.area())
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
1-
class Circle:
1+
class Shape:
2+
def area(self):
3+
pass
4+
5+
6+
class Circle(Shape):
27
def __init__(self, radius):
38
self.radius = radius
49

510
def area(self):
611
return 3.14159 * self.radius * self.radius
712

8-
class Square:
13+
14+
class Square(Shape):
915
def __init__(self, length):
1016
self.length = length
1117

1218
def area(self):
1319
return self.length * self.length
1420

21+
1522
shapes = [Circle(5), Square(10)]
1623
for shape in shapes:
1724
print(shape.area())

0 commit comments

Comments
 (0)