├── 1_do_one_thing_after.py ├── 1_do_one_thing_before.py ├── 2_separate_cmd_query.py ├── 3_keyword_arguments.py ├── 4_minimal_arguments.py ├── 5_create_use_after.py ├── 5_create_use_before.py ├── 6_boolean_flag_after.py ├── 6_boolean_flag_before.py ├── 7_functions_are_objects.py ├── LICENSE └── README.md /1_do_one_thing_after.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from datetime import datetime 3 | 4 | 5 | def luhn_checksum(card_number: str) -> bool: 6 | def digits_of(number: str) -> list[int]: 7 | return [int(d) for d in number] 8 | 9 | digits = digits_of(card_number) 10 | odd_digits = digits[-1::-2] 11 | even_digits = digits[-2::-2] 12 | checksum = 0 13 | checksum += sum(odd_digits) 14 | for digit in even_digits: 15 | checksum += sum(digits_of(str(digit * 2))) 16 | return checksum % 10 == 0 17 | 18 | 19 | @dataclass 20 | class Customer: 21 | name: str 22 | phone: str 23 | cc_number: str 24 | cc_exp_month: int 25 | cc_exp_year: int 26 | cc_valid: bool = False 27 | 28 | 29 | def validate_card(customer: Customer) -> bool: 30 | customer.cc_valid = ( 31 | luhn_checksum(customer.cc_number) 32 | and datetime(customer.cc_exp_year, customer.cc_exp_month, 1) > datetime.now() 33 | ) 34 | return customer.cc_valid 35 | 36 | 37 | def main() -> None: 38 | alice = Customer( 39 | name="Alice", 40 | phone="2341", 41 | cc_number="1249190007575069", 42 | cc_exp_month=1, 43 | cc_exp_year=2024, 44 | ) 45 | is_valid = validate_card(alice) 46 | print(f"Is Alice's card valid? {is_valid}") 47 | print(alice) 48 | 49 | 50 | if __name__ == "__main__": 51 | main() 52 | -------------------------------------------------------------------------------- /1_do_one_thing_before.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from datetime import datetime 3 | 4 | 5 | @dataclass 6 | class Customer: 7 | name: str 8 | phone: str 9 | cc_number: str 10 | cc_exp_month: int 11 | cc_exp_year: int 12 | cc_valid: bool = False 13 | 14 | 15 | def validate_card(customer: Customer) -> bool: 16 | def digits_of(number: str) -> list[int]: 17 | return [int(d) for d in number] 18 | 19 | digits = digits_of(customer.cc_number) 20 | odd_digits = digits[-1::-2] 21 | even_digits = digits[-2::-2] 22 | checksum = 0 23 | checksum += sum(odd_digits) 24 | for digit in even_digits: 25 | checksum += sum(digits_of(str(digit * 2))) 26 | 27 | customer.cc_valid = ( 28 | checksum % 10 == 0 29 | and datetime(customer.cc_exp_year, customer.cc_exp_month, 1) > datetime.now() 30 | ) 31 | return customer.cc_valid 32 | 33 | 34 | def main() -> None: 35 | alice = Customer( 36 | name="Alice", 37 | phone="2341", 38 | cc_number="1249190007575069", 39 | cc_exp_month=1, 40 | cc_exp_year=2024, 41 | ) 42 | is_valid = validate_card(alice) 43 | print(f"Is Alice's card valid? {is_valid}") 44 | print(alice) 45 | 46 | 47 | if __name__ == "__main__": 48 | main() 49 | -------------------------------------------------------------------------------- /2_separate_cmd_query.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from datetime import datetime 3 | 4 | 5 | def luhn_checksum(card_number: str) -> bool: 6 | def digits_of(number: str) -> list[int]: 7 | return [int(d) for d in number] 8 | 9 | digits = digits_of(card_number) 10 | odd_digits = digits[-1::-2] 11 | even_digits = digits[-2::-2] 12 | checksum = 0 13 | checksum += sum(odd_digits) 14 | for digit in even_digits: 15 | checksum += sum(digits_of(str(digit * 2))) 16 | return checksum % 10 == 0 17 | 18 | 19 | @dataclass 20 | class Customer: 21 | name: str 22 | phone: str 23 | cc_number: str 24 | cc_exp_month: int 25 | cc_exp_year: int 26 | cc_valid: bool = False 27 | 28 | 29 | def validate_card(customer: Customer) -> bool: 30 | return ( 31 | luhn_checksum(customer.cc_number) 32 | and datetime(customer.cc_exp_year, customer.cc_exp_month, 1) > datetime.now() 33 | ) 34 | 35 | 36 | def main() -> None: 37 | alice = Customer( 38 | name="Alice", 39 | phone="2341", 40 | cc_number="1249190007575069", 41 | cc_exp_month=1, 42 | cc_exp_year=2024, 43 | ) 44 | alice.cc_valid = validate_card(alice) 45 | print(f"Is Alice's card valid? {alice.cc_valid}") 46 | print(alice) 47 | 48 | 49 | if __name__ == "__main__": 50 | main() 51 | -------------------------------------------------------------------------------- /3_keyword_arguments.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from datetime import datetime 3 | 4 | 5 | def luhn_checksum(card_number: str) -> bool: 6 | def digits_of(number: str) -> list[int]: 7 | return [int(d) for d in number] 8 | 9 | digits = digits_of(card_number) 10 | odd_digits = digits[-1::-2] 11 | even_digits = digits[-2::-2] 12 | checksum = 0 13 | checksum += sum(odd_digits) 14 | for digit in even_digits: 15 | checksum += sum(digits_of(str(digit * 2))) 16 | return checksum % 10 == 0 17 | 18 | 19 | @dataclass 20 | class Customer: 21 | name: str 22 | phone: str 23 | cc_number: str 24 | cc_exp_month: int 25 | cc_exp_year: int 26 | cc_valid: bool = False 27 | 28 | 29 | def validate_card(*, number: str, exp_month: int, exp_year: int) -> bool: 30 | return luhn_checksum(number) and datetime(exp_year, exp_month, 1) > datetime.now() 31 | 32 | 33 | def main() -> None: 34 | alice = Customer( 35 | name="Alice", 36 | phone="2341", 37 | cc_number="1249190007575069", 38 | cc_exp_month=1, 39 | cc_exp_year=2024, 40 | ) 41 | alice.cc_valid = validate_card( 42 | number=alice.cc_number, 43 | exp_month=alice.cc_exp_month, 44 | exp_year=alice.cc_exp_year, 45 | ) 46 | print(f"Is Alice's card valid? {alice.cc_valid}") 47 | print(alice) 48 | 49 | 50 | if __name__ == "__main__": 51 | main() 52 | -------------------------------------------------------------------------------- /4_minimal_arguments.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from datetime import datetime 3 | from typing import Protocol 4 | 5 | 6 | def luhn_checksum(card_number: str) -> bool: 7 | def digits_of(number: str) -> list[int]: 8 | return [int(d) for d in number] 9 | 10 | digits = digits_of(card_number) 11 | odd_digits = digits[-1::-2] 12 | even_digits = digits[-2::-2] 13 | checksum = 0 14 | checksum += sum(odd_digits) 15 | for digit in even_digits: 16 | checksum += sum(digits_of(str(digit * 2))) 17 | return checksum % 10 == 0 18 | 19 | 20 | @dataclass 21 | class Card: 22 | number: str 23 | exp_month: int 24 | exp_year: int 25 | valid: bool = False 26 | 27 | 28 | @dataclass 29 | class Customer: 30 | name: str 31 | phone: str 32 | card: Card 33 | card_valid: bool = False 34 | 35 | 36 | class CardInfo(Protocol): 37 | @property 38 | def number(self) -> str: 39 | ... 40 | 41 | @property 42 | def exp_month(self) -> int: 43 | ... 44 | 45 | @property 46 | def exp_year(self) -> int: 47 | ... 48 | 49 | 50 | def validate_card(card: CardInfo) -> bool: 51 | return ( 52 | luhn_checksum(card.number) 53 | and datetime(card.exp_year, card.exp_month, 1) > datetime.now() 54 | ) 55 | 56 | 57 | def main() -> None: 58 | card = Card(number="1249190007575069", exp_month=1, exp_year=2024) 59 | alice = Customer(name="Alice", phone="2341", card=card) 60 | card.valid = validate_card(card) 61 | print(f"Is Alice's card valid? {card.valid}") 62 | print(alice) 63 | 64 | 65 | if __name__ == "__main__": 66 | main() 67 | -------------------------------------------------------------------------------- /5_create_use_after.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Protocol 3 | 4 | 5 | class StripePaymentHandler: 6 | def handle_payment(self, amount: int) -> None: 7 | logging.info(f"Charging ${amount/100:.2f} using Stripe") 8 | 9 | 10 | PRICES = { 11 | "burger": 10_00, 12 | "fries": 5_00, 13 | "drink": 2_00, 14 | "salad": 15_00, 15 | } 16 | 17 | 18 | class PaymentHandler(Protocol): 19 | def handle_payment(self, amount: int) -> None: 20 | ... 21 | 22 | 23 | def order_food(items: list[str], payment_handler: PaymentHandler) -> None: 24 | total = sum(PRICES[item] for item in items) 25 | logging.info(f"Order total is ${total/100:.2f}.") 26 | payment_handler.handle_payment(total) 27 | logging.info("Order completed.") 28 | 29 | 30 | def main() -> None: 31 | logging.basicConfig(level=logging.INFO) 32 | order_food(["burger", "salad", "drink"], StripePaymentHandler()) 33 | 34 | 35 | if __name__ == "__main__": 36 | main() 37 | -------------------------------------------------------------------------------- /5_create_use_before.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | class StripePaymentHandler: 5 | def handle_payment(self, amount: int) -> None: 6 | logging.info(f"Charging ${amount/100:.2f} using Stripe") 7 | 8 | 9 | PRICES = { 10 | "burger": 10_00, 11 | "fries": 5_00, 12 | "drink": 2_00, 13 | "salad": 15_00, 14 | } 15 | 16 | 17 | def order_food(items: list[str]) -> None: 18 | total = sum(PRICES[item] for item in items) 19 | logging.info(f"Order total is ${total/100:.2f}.") 20 | payment_handler = StripePaymentHandler() 21 | payment_handler.handle_payment(total) 22 | logging.info("Order completed.") 23 | 24 | 25 | def main() -> None: 26 | logging.basicConfig(level=logging.INFO) 27 | order_food(["burger", "fries", "drink"]) 28 | 29 | 30 | if __name__ == "__main__": 31 | main() 32 | -------------------------------------------------------------------------------- /6_boolean_flag_after.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from enum import StrEnum, auto 3 | 4 | FIXED_VACATION_DAYS_PAYOUT = 5 5 | 6 | 7 | class Role(StrEnum): 8 | PRESIDENT = auto() 9 | VICEPRESIDENT = auto() 10 | MANAGER = auto() 11 | LEAD = auto() 12 | ENGINEER = auto() 13 | INTERN = auto() 14 | 15 | 16 | @dataclass 17 | class Employee: 18 | name: str 19 | role: Role 20 | vacation_days: int = 25 21 | 22 | def payout_holiday(self) -> None: 23 | if self.vacation_days < FIXED_VACATION_DAYS_PAYOUT: 24 | raise ValueError( 25 | f"You don't have enough holidays left over for a payout.\ 26 | Remaining holidays: {self.vacation_days}." 27 | ) 28 | self.vacation_days -= FIXED_VACATION_DAYS_PAYOUT 29 | print(f"Paying out a holiday. Holidays left: {self.vacation_days}") 30 | 31 | def take_holiday(self, nr_days: int = 1) -> None: 32 | if self.vacation_days < nr_days: 33 | raise ValueError("You don't have any holidays left. Now back to work, you!") 34 | self.vacation_days -= nr_days 35 | print("Have fun on your holiday. Don't forget to check your emails!") 36 | 37 | 38 | def main() -> None: 39 | employee = Employee(name="John Doe", role=Role.ENGINEER) 40 | employee.payout_holiday() 41 | 42 | 43 | if __name__ == "__main__": 44 | main() 45 | -------------------------------------------------------------------------------- /6_boolean_flag_before.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from enum import StrEnum, auto 3 | 4 | FIXED_VACATION_DAYS_PAYOUT = 5 5 | 6 | 7 | class Role(StrEnum): 8 | PRESIDENT = auto() 9 | VICEPRESIDENT = auto() 10 | MANAGER = auto() 11 | LEAD = auto() 12 | ENGINEER = auto() 13 | INTERN = auto() 14 | 15 | 16 | @dataclass 17 | class Employee: 18 | name: str 19 | role: Role 20 | vacation_days: int = 25 21 | 22 | def take_a_holiday(self, payout: bool, nr_days: int = 1) -> None: 23 | if payout: 24 | if self.vacation_days < FIXED_VACATION_DAYS_PAYOUT: 25 | raise ValueError( 26 | f"You don't have enough holidays left over for a payout.\ 27 | Remaining holidays: {self.vacation_days}." 28 | ) 29 | self.vacation_days -= FIXED_VACATION_DAYS_PAYOUT 30 | print(f"Paying out a holiday. Holidays left: {self.vacation_days}") 31 | else: 32 | if self.vacation_days < nr_days: 33 | raise ValueError( 34 | "You don't have any holidays left. Now back to work, you!" 35 | ) 36 | self.vacation_days -= nr_days 37 | print("Have fun on your holiday. Don't forget to check your emails!") 38 | 39 | 40 | def main() -> None: 41 | employee = Employee(name="John Doe", role=Role.ENGINEER) 42 | employee.take_a_holiday(True) 43 | 44 | 45 | if __name__ == "__main__": 46 | main() 47 | -------------------------------------------------------------------------------- /7_functions_are_objects.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from functools import partial 3 | from typing import Callable 4 | 5 | 6 | def handle_payment_stripe(amount: int) -> None: 7 | logging.info(f"Charging ${amount/100:.2f} using Stripe") 8 | 9 | 10 | PRICES = { 11 | "burger": 10_00, 12 | "fries": 5_00, 13 | "drink": 2_00, 14 | "salad": 15_00, 15 | } 16 | 17 | 18 | HandlePaymentFn = Callable[[int], None] 19 | 20 | 21 | def order_food(items: list[str], payment_handler: HandlePaymentFn) -> None: 22 | total = sum(PRICES[item] for item in items) 23 | logging.info(f"Order total is ${total/100:.2f}.") 24 | payment_handler(total) 25 | logging.info("Order completed.") 26 | 27 | 28 | order_food_stripe = partial(order_food, payment_handler=handle_payment_stripe) 29 | 30 | 31 | def main() -> None: 32 | logging.basicConfig(level=logging.INFO) 33 | # order_food(["burger", "salad", "drink"], handle_payment_stripe) 34 | order_food_stripe(["burger", "salad", "drink"]) 35 | 36 | 37 | if __name__ == "__main__": 38 | main() 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 ArjanCodes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Ultimate Guide to Writing Functions 2 | 3 | Video link: https://youtu.be/yatgY4NpZXE. 4 | --------------------------------------------------------------------------------