Skip to content

Commit 7f64188

Browse files
authored
Merge pull request #398 from hfhoffman1144/self_type
Code for the Python Self Type Article
2 parents d531345 + 66a4e15 commit 7f64188

File tree

8 files changed

+308
-0
lines changed

8 files changed

+308
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Python's Self Type: How to Annotate Methods That Return self
2+
3+
This folder provides the code examples for the Real Python tutorial [Python's Self Type: How to Annotate Methods That Return Self](https://realpython.com/python-type-self/).
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from dataclasses import dataclass
2+
from typing import Self
3+
import random
4+
5+
6+
@dataclass
7+
class BankAccount:
8+
account_number: int
9+
balance: float
10+
11+
def display_balance(self) -> Self:
12+
print(f"Account Number: {self.account_number}")
13+
print(f"Balance: ${self.balance:,.2f}\n")
14+
return self
15+
16+
def deposit(self, amount: float) -> Self:
17+
self.balance += amount
18+
return self
19+
20+
def withdraw(self, amount: float) -> Self:
21+
if self.balance >= amount:
22+
self.balance -= amount
23+
else:
24+
print("Insufficient balance")
25+
return self
26+
27+
28+
@dataclass
29+
class SavingsAccount(BankAccount):
30+
interest_rate: float
31+
32+
@classmethod
33+
def from_application(
34+
cls, deposit: float = 0, interest_rate: float = 1
35+
) -> Self:
36+
# Generate a random seven-digit bank account number
37+
account_number = random.randint(1000000, 9999999)
38+
return cls(account_number, deposit, interest_rate)
39+
40+
def calculate_interest(self) -> float:
41+
return self.balance * self.interest_rate / 100
42+
43+
def add_interest(self) -> Self:
44+
self.deposit(self.calculate_interest())
45+
return self
46+
47+
48+
account = BankAccount(account_number=1534899324, balance=50)
49+
(
50+
account.display_balance()
51+
.deposit(50)
52+
.display_balance()
53+
.withdraw(30)
54+
.display_balance()
55+
)
56+
57+
savings = SavingsAccount.from_application(deposit=100, interest_rate=5)
58+
(
59+
savings.display_balance()
60+
.add_interest()
61+
.display_balance()
62+
.deposit(50)
63+
.display_balance()
64+
.withdraw(30)
65+
.add_interest()
66+
.display_balance()
67+
)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from __future__ import annotations
2+
from dataclasses import dataclass
3+
import random
4+
5+
6+
@dataclass
7+
class BankAccount:
8+
account_number: int
9+
balance: float
10+
11+
def display_balance(self) -> BankAccount:
12+
print(f"Account Number: {self.account_number}")
13+
print(f"Balance: ${self.balance:,.2f}\n")
14+
return self
15+
16+
def deposit(self, amount: float) -> BankAccount:
17+
self.balance += amount
18+
return self
19+
20+
def withdraw(self, amount: float) -> BankAccount:
21+
if self.balance >= amount:
22+
self.balance -= amount
23+
else:
24+
print("Insufficient balance")
25+
return self
26+
27+
28+
@dataclass
29+
class SavingsAccount(BankAccount):
30+
interest_rate: float
31+
32+
@classmethod
33+
def from_application(
34+
cls, deposit: float = 0, interest_rate: float = 1
35+
) -> SavingsAccount:
36+
# Generate a random seven-digit bank account number
37+
account_number = random.randint(1000000, 9999999)
38+
return cls(account_number, deposit, interest_rate)
39+
40+
def calculate_interest(self) -> float:
41+
return self.balance * self.interest_rate / 100
42+
43+
def add_interest(self) -> SavingsAccount:
44+
self.deposit(self.calculate_interest())
45+
return self
46+
47+
48+
account = BankAccount(account_number=1534899324, balance=50)
49+
(
50+
account.display_balance()
51+
.deposit(50)
52+
.display_balance()
53+
.withdraw(30)
54+
.display_balance()
55+
)
56+
57+
savings = SavingsAccount.from_application(deposit=100, interest_rate=5)
58+
(
59+
savings.display_balance()
60+
.add_interest()
61+
.display_balance()
62+
.deposit(50)
63+
.display_balance()
64+
.withdraw(30)
65+
.add_interest()
66+
.display_balance()
67+
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from __future__ import annotations
2+
from typing import Any
3+
4+
5+
class Stack:
6+
def __init__(self) -> None:
7+
self.items: list[Any] = []
8+
9+
def push(self, item: Any) -> Stack:
10+
self.items.append(item)
11+
return self
12+
13+
def pop(self) -> Any:
14+
if self.__bool__():
15+
return self.items.pop()
16+
else:
17+
raise ValueError("Stack is empty")
18+
19+
def __bool__(self) -> bool:
20+
return len(self.items) > 0
21+
22+
23+
stack = Stack()
24+
stack.push(1).push(2).push(3).pop()
25+
print(stack.items)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from typing import Any, Self
2+
3+
# from typing_extensions import Self - for Python < 3.11
4+
5+
6+
class Stack:
7+
def __init__(self) -> None:
8+
self.items: list[Any] = []
9+
10+
def push(self, item: Any) -> Self:
11+
self.items.append(item)
12+
return self
13+
14+
def pop(self) -> Any:
15+
if self.__bool__():
16+
return self.items.pop()
17+
else:
18+
raise ValueError("Stack is empty")
19+
20+
def __bool__(self) -> bool:
21+
return len(self.items) > 0
22+
23+
24+
stack = Stack()
25+
stack.push(1).push(2).push(3).pop()
26+
print(stack.items)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from typing import Any
2+
3+
4+
class Stack:
5+
def __init__(self) -> None:
6+
self.items: list[Any] = []
7+
8+
def push(self, item: Any) -> "Stack":
9+
self.items.append(item)
10+
return self
11+
12+
def pop(self) -> Any:
13+
if self.__bool__():
14+
return self.items.pop()
15+
else:
16+
raise ValueError("Stack is empty")
17+
18+
def __bool__(self) -> bool:
19+
return len(self.items) > 0
20+
21+
22+
stack = Stack()
23+
stack.push(1).push(2).push(3).pop()
24+
print(stack.items)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from dataclasses import dataclass
2+
from typing import TypeVar
3+
import random
4+
5+
# Create TBankAccount type bound by the BankAccount class
6+
TBankAccount = TypeVar("TBankAccount", bound="BankAccount")
7+
8+
9+
@dataclass
10+
class BankAccount:
11+
account_number: int
12+
balance: float
13+
14+
def display_balance(self: TBankAccount) -> TBankAccount:
15+
print(f"Account Number: {self.account_number}")
16+
print(f"Balance: ${self.balance:,.2f}\n")
17+
return self
18+
19+
def deposit(self: TBankAccount, amount: float) -> TBankAccount:
20+
self.balance += amount
21+
return self
22+
23+
def withdraw(self: TBankAccount, amount: float) -> TBankAccount:
24+
if self.balance >= amount:
25+
self.balance -= amount
26+
else:
27+
print("Insufficient balance")
28+
return self
29+
30+
31+
@dataclass
32+
class SavingsAccount(BankAccount):
33+
interest_rate: float
34+
35+
@classmethod
36+
def from_application(
37+
cls: type[TBankAccount], deposit: float = 0, interest_rate: float = 1
38+
) -> TBankAccount:
39+
# Generate a random seven-digit bank account number
40+
account_number = random.randint(1000000, 9999999)
41+
return cls(account_number, deposit, interest_rate)
42+
43+
def calculate_interest(self) -> float:
44+
return self.balance * self.interest_rate / 100
45+
46+
def add_interest(self: TBankAccount) -> TBankAccount:
47+
self.deposit(self.calculate_interest())
48+
return self
49+
50+
51+
account = BankAccount(account_number=1534899324, balance=50)
52+
(
53+
account.display_balance()
54+
.deposit(50)
55+
.display_balance()
56+
.withdraw(30)
57+
.display_balance()
58+
)
59+
60+
savings = SavingsAccount.from_application(deposit=100, interest_rate=5)
61+
(
62+
savings.display_balance()
63+
.add_interest()
64+
.display_balance()
65+
.deposit(50)
66+
.display_balance()
67+
.withdraw(30)
68+
.add_interest()
69+
.display_balance()
70+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from typing import Any, TypeVar
2+
3+
TStack = TypeVar("TStack", bound="Stack")
4+
5+
6+
class Stack:
7+
def __init__(self) -> None:
8+
self.items: list[Any] = []
9+
10+
def push(self: TStack, item: Any) -> TStack:
11+
self.items.append(item)
12+
return self
13+
14+
def pop(self) -> Any:
15+
if self.__bool__():
16+
return self.items.pop()
17+
else:
18+
raise ValueError("Stack is empty")
19+
20+
def __bool__(self) -> bool:
21+
return len(self.items) > 0
22+
23+
24+
stack = Stack()
25+
stack.push(1).push(2).push(3).pop()
26+
print(stack.items)

0 commit comments

Comments
 (0)