0% found this document useful (0 votes)
7 views

02 Python Typing

The document provides an overview of Python typing, including its dynamic nature, type hints, and verification techniques. It covers advanced typing techniques such as defining types for functions and methods, abstract classes, and creating new types. Additionally, it discusses function overloading and how to implement it in Python.

Uploaded by

Ivan Igic
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

02 Python Typing

The document provides an overview of Python typing, including its dynamic nature, type hints, and verification techniques. It covers advanced typing techniques such as defining types for functions and methods, abstract classes, and creating new types. Additionally, it discusses function overloading and how to implement it in Python.

Uploaded by

Ivan Igic
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 23

Click to edit

Python Master title style


Typing

1. Getting started with Python typing


2. Python typing techniques
3. Defining abstract classes/methods

Annex
• Additional techniques
Section 1: Getting Started with Python
Click to edit Master title style
Typing
• Python is dynamically typed
• Providing type hints
• How to verify Python type usage
• Python types available
Python is Dynamically Typed
Click to edit Master title style
• Python is a dynamically-typed language
• A variable can change its type mid-flight
x = 42
print(x, type(x))

x = "Hello world"
print(x, type(x))
Ex01_PythonIsDynamicallyTyped.py

• Pros of dynamic typing:


• Python code is easy to learn/write

• Cons of dynamic typing:


• Python code can be error-prone at run time
Providing Type Hints
Click to edit Master title style
• You can provide type hints for your variables
• When you declare a variable, specify its intended type too
y: int = 42

y = 43 # OK

y = "Hello" # Not OK
Ex02_ProvidingTypeHints.py

• Pros of type hints:


• Enables static code checkers to spot incorrect type usage

• Cons of dynamic typing:


• More syntax to learn/write
• Not enforced at run time (Python is still dynamically typed!)
How to Verify Python Type Usage
Click to edit Master title style
• There are various static code checkers available, to verify
that your code adheres to the specified types
• We'll use pyright, a popular choice

• Install and run pyright as follows:


pip install pyright

pyright <filename.py>

• For example:
Python Types Available
Click to edit Master title style
• You can define type hints for all the simple Python types:
a: int = 42

b: float = 3.14

c: bool = True

d: list[int] = [10, 20, 30]

e: set[str] = {"Swansea", "Wrexham", "Newport", "Swansea"}

f: dict[str, str] = {"UK": "+44", "DK": "+45", "SE": "+46", "NO": "+47"}

g: tuple[str, float, float] = ("Swansea", 51.62, -3.94)

print(a, b, c, d, e, f, g)
Ex03_PythonTypesAvailable.py
Section 2: Python Typing Techniques
Click to edit Master title style
• Defining type hints for functions
• Type techniques
• Defining type hints for methods
Defining Type Hints for Functions
Click to edit Master title style
• You can define types for function arguments/returns…

• Simple argument / return types:


def calc_discriminant(a: float, b: float, c: float) -> float: ...

• Returning something interesting:


def calc_roots(a: float, b: float, c: float) -> tuple[float, float]: ...

• Receiving variadic positional arguments:


def display_squares(*nums: int) -> None: ...

• Receiving variadic keyword arguments:


def display_named_squares(**kwargs: int) -> None: ...
Ex04_Functions.py
Type Techniques (1 of 2)
Click to edit Master title style
• There are some interesting type techniques you can use...

• Defining a union type


def f1(a: str | int | float) -> str: ...

• Defining an optional parameter:


def f2(fav_football_team: Optional[str] = None) -> None: ...

• Allowing any type of parameter:


def f3(arg: Any) -> None: ...
Ex05a_TypeTechniques.py

• Note:
• Optional and Any are located in the typing module
Type Techniques (2 of 2)
Click to edit Master title style
• You can define the signature of lambdas
• Via Callable in the typing module
from typing import Callable

def apply(a: int, b: int, op: Callable[[int,int], int]) -> int :


print("In apply()")
return op(a, b)

res1 = apply(10, 20, lambda x, y: x + y)


print(res1)

res2 = apply(10, 20, lambda x, y: x - y)


print(res2)

res3 = apply(10, 20, lambda x, y: x * y)


print(res3)
Ex05b_TypeTechniques.py
Defining Type Hints for Methods
Click to edit Master title style
• You can define type hints for methods in a class
• You can use Self as an alias for the current class name
from typing import Self

class Person:

def __init__(self: Self, name: str, age: int) -> None:


self.name = name
self.age = age

def isOlderThan(self: Self, other: Self) -> bool:


return self.age > other.age

• You can also use a class name as a type hint


def display_person(p: Person) -> None:
print(f"{p.name} is {p.age} years old")
Ex06_Methods.py
Section 3: Defining Abstract
Click to edit Master
Classes/Methods title style
• Overview of abstract classes/methods
• Defining an abstract class
• Defining concrete subclasses
Overview of Abstract Classes/Methods
Click to edit Master title style
• Abstract classes and abstract methods are important
concepts in OO programming…

• An abstract class…
• Is a class you can't instantiate
• Instead, you instantiate concrete subclasses

• An abstract method…
• Is a method specified (but not implemented) in an abstract
class
• All concrete subclasses must override/implement the method
Defining an Abstract Class
Click to edit Master title style
• Python has a handy module named abc
• Helps you define abstract classes and abstract methods

• To define an abstract class:


• Inherit from abc.ABC
• Define empty methods, decorated with
@abc.abstractmethod
import abc

class shape(abc.ABC):

@abc.abstractmethod
def area(self: Self) -> float: ...

@abc.abstractmethod
def perimeter(self: Self) -> float: ...
Ex07_AbstractClass.py
Defining Concrete Classes
Click to edit Master title style
• To define a concrete subclass:
• Inherit from a superclass
• Provide an implementation for all abstract methods

👍
class quadrilateral(shape):

def area(self: Self) -> float:


return self.width * self.height

def perimeter(self: Self) -> float:


return 2 * (self.width + self.height)

class circle(shape):

def area(self: Self) -> float:


return pi * self.radius ** 2

👎 def circumference(self: Self) -> float:


return 2 * pi * self.radius
# Oops!

Ex08_ConcreteSubclasses.py
Click to edit Master title style
Summary

• Getting started with Python typing


• Python typing techniques
• Defining abstract classes/methods
Annex: Additional Techniques
Click to edit Master title style
• Defining type hints for class objects
• Creating new types
• Function overloading
Defining Types Hints for Class Objects
Click to edit Master title style
• When you define a class in Python…
• Python creates a class object describing it (class name,
methods, etc.)

• You can pass a class object into functions


• And
from you
typing can Self,
import use Type[classname]
Type to provide a type hint
Ex09_ClassObjects.py

class Person: ...


class Student(Person): ...
class Employee(Person): ...

def create_kind_of_person(cls: Type[Person], name: str, age: int) -> Person:


if age > 125:
raise ValueError("How old???")
return cls(name, age)

p1 = create_kind_of_person(Student, "William", 20)


p2 = create_kind_of_person(Employee, "Kate", 30)
Creating New Types (1 of 2)
Click to edit Master title style
• Consider the following simple class:
class Employee:

def __init__(self: Self, name: str, id: int, salary: int) -> None:
self.name = name
self.id = id
self.salary = salary

def __str__(self: Self) -> str:


return f"[{self.id} {self.name}, earns {self.salary} ]"

emp1 = Employee("Mary", 1, 10000)


emp2 = Employee("Mungo", 2, 20000) Ex08a_NewTypes_Bad.py
emp3 = Employee("Midge", 30000, 3)
Ex10a_NewTypes_Lax.py

• The Employee constructor receives two int arguments


• We could accidentally pass in ints in the wrong order (see
Midge), and this would not be detected as a type error 😢
Creating New Types (2 of 2)
Click to edit Master title style
• You can use Python typing to invent distinct types:
from typing import Self, NewType

Money = NewType(Money', int) # Money is a new type, inherits from int.


PK = NewType('PK', int) # PK is a new type, inherits from int.

class Employee:

def __init__(self: Self, name: str, id: PK, salary: Money) -> None:
self.name = name
self.id = id
self.salary = salary

def __str__(self: Self) -> str:


return f"[{self.id} {self.name}, earns {self.salary} ]"

emp1 = Employee("Mary", PK(1), Money(10000)) # Must specify exact arg types


emp2 = Employee("Mungo", PK(2), Money(20000))
emp3 = Employee("Midge", PK(3), Money(30000))
Ex10b_NewTypes_Strict.py
Function Overloading (1 of 3)
Click to edit Master title style
• Python typing lets you define overloaded functions
• Multiple functions with the same name, but different args
• (The number or type of args must be different)

• Here's a simple example of using overloaded functions:


res1 = seconds_to_midnight(86_395) # Pass in time of day as (seconds)
res2 = seconds_to_midnight(23, 59, 57) # Pass in time of day as (h, m, s)

• Let's see how to do this using Python typing…


Function Overloading (2 of 3)
Click to edit Master title style
• First, specify the function signatures you want to support
• Decorate these functions with @overload
from typing import overload

@overload
def seconds_to_midnight(p1: int) -> int: ...

@overload
def seconds_to_midnight(p1: int, p2: int, p3: int) -> int: ...

• Then, define a single function that satisfies all signatures:


def seconds_to_midnight(
p1: int,
p2: int | None = None,
p3: int | None = None) -> int:

# Implementation to satisfy both overloads. See next slide…


Ex11_FunctionOverloading.py
Function Overloading (3 of 3)
Click to edit Master title style
• The function implementation must figure out which
overload the client called:
def seconds_to_midnight(
p1: int,
p2: int | None = None,
p3: int | None = None) -> int:

NUM_SECS_IN_DAY = 60*60*24

if (p2 is None or p3 is None): seconds_to_midnight(86_395)


return NUM_SECS_IN_DAY - p1

else: seconds_to_midnight(23, 59, 57)


return NUM_SECS_IN_DAY - (p1*60*60 + p2*60 + p3)
Ex11_FunctionOverloading.py

You might also like