SLIDE 1
Type hints w jzyku Python Konrad Haas 4Developers 2018 Plan type - - PowerPoint PPT Presentation
Type hints w jzyku Python Konrad Haas 4Developers 2018 Plan type - - PowerPoint PPT Presentation
Type hints w jzyku Python Konrad Haas 4Developers 2018 Plan type hints dlaczego? skadnia narzdzia biblioteki projekty legacy def notify_everyone (items): for item in items: item.owner.notify() def cancel_all (items):
SLIDE 2
SLIDE 3
SLIDE 4
SLIDE 5
SLIDE 6
Plan
type hints dlaczego? składnia narzędzia biblioteki projekty legacy
SLIDE 7
def notify_everyone(items): for item in items: item.owner.notify()
SLIDE 8
def cancel_all(items): notify_everyone(items) ...
SLIDE 9
Rozwiązania
dokumentacja zewnętrzna dokumentacja w kodzie (RST, epytext, NumPy, Google) przepisać wszystko do języka statycznie typowanego
SLIDE 10
SLIDE 11
def count_unique_words(text, case_sensitive): ...
SLIDE 12
def count_unique_words(text: str, case_sensitive: bool) ‑> int: ...
SLIDE 13
def median(values: list) ‑> float: ...
SLIDE 14
from typing import List def median(values: List[float]) ‑> float: ...
SLIDE 15
from typing import Dict def count_chars(text: str) ‑> Dict[str, int]: ...
SLIDE 16
from typing import List class Point: ... def calculate_area(vertices: List[Point]) ‑> float: ...
SLIDE 17
from typing import Optional def total_amount(order: Order, discount: Optional[Discount]) ‑> Money: ...
SLIDE 18
from typing import List, Union def send_confirmation(email: Union[str, List[str]]) ‑> None: ...
SLIDE 19
from typing import Any def get_most_frequent(items: list) ‑> Any: ...
SLIDE 20
from typing import List, TypeVar T = TypeVar('T') def get_most_frequent(items: List[T]) ‑> T: ...
SLIDE 21
SLIDE 22
from typing import List class Item: ... class Basket: def __init__(self): self.items: List[Item] = [] def add_item(self, item: Item): self.items.append(item)
SLIDE 23
Narzędzia
mypy PyCharm ...
SLIDE 24
def total_price(items: List[Item], discount: Optional[float] = None) ‑> float: ...
SLIDE 25
def total_price(items: List[Item], discount: Optional[float] = None) ‑> float: result = 0.0 for item in items: result += item.count * item.product.price result ‑= discount return result
SLIDE 26
def total_price(items: List[Item], discount: Optional[float] = None) ‑> float: result = 0.0 for item in items: result += item.count * item.product.price result ‑= discount return result $ mypy ‑‑strict example.py example.py:9: error: "Item" has no attribute "count" example.py:10: error: Unsupported operand types for ‑ ("float" and "Optional[float]")
SLIDE 27
def total_price(items: List[Item], discount: Optional[float] = None) ‑> float: result = 0.0 for item in items: result += item.quantity * item.product.price if discount: result ‑= discount return result $ mypy ‑‑strict example.py
SLIDE 28
SLIDE 29
SLIDE 30
Biblioteki
injector dacite ...
SLIDE 31
def register_user(user_details: UserDetails): ...
SLIDE 32
from users.repositories import UsersRepository def register_user(user_details: UserDetails): ... repository = UsersRepository() repository.create_user(...)
SLIDE 33
class UsersService: def __init__(self, repository: UsersRepository): self.repository = repository def register_user(self, user_details: UserDetails): ... self.repository.create_user(...)
SLIDE 34
class UsersRepository: def __init__(self, data_base: DataBase): self.data_base = data_base def create_user(self, user: User): ... self.data_base.insert(...)
SLIDE 35
class DataBase: def __init__(self, session: DataBaseSession): self.session = session ...
SLIDE 36
session = DataBaseSession(...) data_base = DataBase(session) users_repository = UsersRepository(data_base) users_service = UsersService(users_repository)
SLIDE 37
class DataBaseSession: ... class DataBase: def __init__(self, session: DataBaseSession): ... class UsersRepository: def __init__(self, database: DataBase): ... class UsersService: def __init__(self, repository: UsersRepository): ...
SLIDE 38
from injector import inject class DataBaseSession: ... class DataBase: @inject def __init__(self, session: DataBaseSession): ... class UsersRepository: @inject def __init__(self, database: DataBase): ... class UsersService: @inject def __init__(self, repository: UsersRepository): ...
SLIDE 39
from injector import Injector users_service = Injector().get(UsersService)
SLIDE 40
from dataclasses import dataclass @dataclass class User: name: str age: int is_active: bool user = User(name='John', age=30, is_active=True)
SLIDE 41
import dacite data = { 'name': 'John', 'age': 30, 'is_active': True, } user = dacite.from_dict(data_class=User, data=data) assert user == User(name='John', age=30, is_active=True)
SLIDE 42
Type hints w projekcie legacy
gradual typing statyczna analiza uruchamiana w ramach CI wymuszanie type annotations dla: kluczowych modułów interfejsów
SLIDE 43
Podsumowanie
zrozumiały kod mniej błędów nowe możliwości
SLIDE 44
Dziękuję!
@konradhalas / konradhalas.pl
SLIDE 45
Zdjęcia
Jacek Kołodziej ‑ http://kolodziejj.info/ Korsan Studio ‑ http://facebook.com/korsanstudio
SLIDE 46