14.6. Function Recap
Automate repetitive tasks
Allow code reuse
Improve code readability
Clean-up code
Allow easier refactoring
14.6.1. Define and Call
Use
snake_case
Do not use
camelCase
Do not use
PascalCase
Use
pass
keyword to define empty function
>>> def run():
... pass
>>>
>>> run()
14.6.2. Return and Capture Results
There could be multiple
return
keywords in a functionCode after first
return
will not executeFunction in Python always returns a value
Function will
return None
if no explicit return is specified
>>> def run():
... return 'something'
...
>>> x = run()
>>> print(x)
something
14.6.3. Parameters
Parameter - what you specify while defining a function
Parameters could be required or default
Required parameter - necessary to call that function, specified at leftmost side
Default parameter - optional to call that function, has default value, can be overridden, specified at rightmost side
Required parameters:
>>> def run(a, b):
... pass
Default parameters:
>>> def run(a=1, b=2):
... pass
Required and default parameters:
>>> def run(a, b=0):
... pass
14.6.4. Arguments
Argument - what you specify while calling a function
Arguments could be positional or keyword
Positional argument - value passed to function resolved by position - order is important
Keyword argument - value passed to function resolved by name - order is not important
Positional arguments:
>>> run(1, 2)
Keyword arguments:
>>> run(a=1, b=2)
Positional and keyword arguments:
>>> run(1, b=2)
14.6.5. Scope
Function can have local variables
Local variables are destroyed when function returns
Functions can access variables in global scope
Global variables are not destroyed when function returns
Shadowing is when you define local variable with the same name as variable global scope
Function will prefer local variable over global
After function return, the original value of a shadowed variable is restored
Function can modify global variables using
global
keyword (this is a bad practice)Builtin function
globals()
returns dictionary of global variablesBuiltin function
locals()
returns dictionary of local variablesIn global scope
locals()
andglobals()
are the sameIn function scope
locals()
andglobals()
are different
Accessing local variable:
>>> def run():
... x = 1
... print(x) # function will access local variable
Accessing global variable:
>>> x = 1
>>>
>>> def run():
... print(x) # function will access global variable
Shadowing:
>>> x = 1 # global variable
>>>
>>> def run():
... x = 10 # local variable with the same name as global
... print(x) # function will prefer local variable
Return deletes local variables (restores shadowed global variables):
>>> x = 1
>>>
>>> def run():
... x = 10
... print(x)
>>> x
1
>>> run()
10
>>> x
1
Modify global variable (considered as a bad practice):
>>> x = 1
>>>
>>> def run():
... global x
... x = 10
... print(x)
Locals vs. Globals:
>>> print(locals() == globals())
True
>>> def run():
... print(locals() == globals())
...
>>> run()
False
14.6.6. Assignments
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Usecase Min
# - Difficulty: easy
# - Lines: 6
# - Minutes: 5
# %% English
# 1. Define function `mymin`:
# - takes `data: list[int|float]`
# - returns lowest value in `data`
# 2. Do not use built-in function `min()`
# 3. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj funkcję `mymin`:
# - przyjmuje `data: list[int|float]`
# - zwraca tuplę z najmniejszą wartością z `data`
# 2. Nie używaj wbudowanej funkcji `min()`
# 3. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from inspect import isfunction
>>> assert mymin is not Ellipsis, \
'Write solution inside `mymin` function'
>>> assert isfunction(mymin), \
'Object `mymin` must be a function'
>>> mymin([3,1,2])
1
>>> mymin([3,1,2,6,4,5])
1
"""
# Define function `mymin`:
# - takes `data: list[int|float]`
# - returns tuple with min and max value from `data`
# Do not use built-in `min()` and `max()` functions
# type: Callable[[list[int|float]], int]
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Usecase Max
# - Difficulty: easy
# - Lines: 6
# - Minutes: 5
# %% English
# 1. Define function `mymax`:
# - takes `data: list[int|float]`
# - returns the greatest value in `data`
# 2. Do not use built-in function `max()`
# 3. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj funkcję `mymax`:
# - przyjmuje `data: list[int|float]`
# - zwraca tuplę z największą wartością z `data`
# 2. Nie używaj wbudowanej funkcji `max()`
# 3. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from inspect import isfunction
>>> assert mymax is not Ellipsis, \
'Write solution inside `mymax` function'
>>> assert isfunction(mymax), \
'Object `mymax` must be a function'
>>> mymax([3,1,2])
3
>>> mymax([3,1,2,6,4,5])
6
"""
# Define function `mymax`:
# - takes `data: list[int|float]`
# - returns tuple with min and max value from `data`
# Do not use built-in `min()` and `max()` functions
# type: Callable[[list[int|float]], int]
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Usecase Len
# - Difficulty: easy
# - Lines: 5
# - Minutes: 5
# %% English
# 1. Define function `mylen`:
# - takes `data: list`
# - returns number of elements in `data`
# 2. Do not use built-in `len()` function
# 3. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj funkcję `mylen`:
# - przyjmuje `data: list`
# - zwraca liczbe elementów w `data`
# 2. Nie używaj wbudowanej funkcji `len`
# 3. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from inspect import isfunction
>>> assert mylen is not Ellipsis, \
'Write solution inside `mylen` function'
>>> assert isfunction(mylen), \
'Object `mylen` must be a function'
>>> mylen([1,2,3])
3
>>> mylen([1,2,3,4,5,6])
6
"""
# Define function `mylen`:
# - takes `data: list`
# - returns number of elements in `data`
# Do not use built-in `len()` function
# type: Callable[[list], int]
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Arguments Range
# - Difficulty: easy
# - Lines: 7
# - Minutes: 5
# %% English
# 1. Define function `myrange` with parameters: `start`, `stop`, `step`
# 2. Write own implementation of a built-in function
# `myrange(start, stop, step)`
# 3. Do not use built-in `range()` function
# 4. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj funkcję `myrange` z parametrami: `start`, `stop`, `step`
# 2. Zaimplementuj własne rozwiązanie wbudowanej funkcji
# `myrange(start, stop, step)`
# 3. Nie używaj wbudowanej funkcji `range()`
# 4. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `while`
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from inspect import isfunction
>>> assert myrange is not Ellipsis, \
'Write solution inside `myrange` function'
>>> assert isfunction(myrange), \
'Object `myrange` must be a function'
>>> myrange(0, 10, 2)
[0, 2, 4, 6, 8]
>>> myrange(0, 5)
[0, 1, 2, 3, 4]
"""
# Define function `myrange` with parameters: `start`, `stop`, `step`
# Write own implementation of a built-in function
# `myrange(start, stop, step)`
# Do not use built-in `range()` function
# type: Callable[[int, int, int], list[int]]
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Usecase Enumerate
# - Difficulty: easy
# - Lines: 7
# - Minutes: 5
# %% English
# 1. Define function `myenumerate`:
# - takes `data: list`
# - returns tuple list with consecutive number and value from `data`
# 2. Example:
# - input: ['red', 'green', 'blue']
# - output: [(0, 'red'), (1, 'green'), (2, 'blue')]
# 3. Do not use built-in `enumerate()` function
# 4. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj funkcję `myenumerate`:
# - przyjmuje `data: list`
# - zwraca listę tupli z kolejnym numerem i wartością z `data`
# 2. Przykład:
# - input: ['red', 'green', 'blue']
# - output: [(0, 'red'), (1, 'green'), (2, 'blue')]
# 3. Nie używaj wbudowanej funkcji `enumerate`
# 4. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from inspect import isfunction
>>> assert myenumerate is not Ellipsis, \
'Write solution inside `myenumerate` function'
>>> assert isfunction(myenumerate), \
'Object `myenumerate` must be a function'
>>> myenumerate(['red', 'green', 'blue'])
[(0, 'red'), (1, 'green'), (2, 'blue')]
"""
# Define function `myenumerate`:
# - takes `data: list`
# - returns number of elements in `data`
# Do not use built-in `len()` function
# type: Callable[[list], int]
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Usecase Zip
# - Difficulty: easy
# - Lines: 8
# - Minutes: 5
# %% English
# 1. Define function `myzip`:
# - takes two parameters `a: list`, `b: list`
# - pairs `a` elements with `b` elements in form of `list[tuple]`
# - first from `a` is paired with first from `b`, etc.
# - collect number of pairs equal to the count of shortest list
# 2. Example:
# - input: ['Mark', 'Melissa'] and ['Watney', 'Lewis']
# - output: [('Mark', 'Watney'), ('Melissa', 'Lewis')]
# 3. Do not use built-in `zip()` function
# 4. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj funkcję `myzip`:
# - przyjmuje `data: list`
# - paruje elementy `a` z elementami z `b` w formie `list[tuple]`
# - pierwszy z `a` ma być sparowany z pierwszym z `b`, itd.
# - zbierz tyle par ile bło wartości w najkrótszej liście
# 2. Przykład:
# - input: ['Mark', 'Melissa'] i ['Watney', 'Lewis']
# - output: [('Mark', 'Watney'), ('Melissa', 'Lewis')]
# 3. Nie używaj wbudowanej funkcji `zip`
# 4. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from inspect import isfunction
>>> assert myzip is not Ellipsis, \
'Write solution inside `myzip` function'
>>> assert isfunction(myzip), \
'Object `myzip` must be a function'
>>> firstnames = ['Mark', 'Melissa', 'Rick']
>>> lastnames = ['Watney', 'Lewis', 'Martinez']
>>> myzip(firstnames, lastnames)
[('Mark', 'Watney'), ('Melissa', 'Lewis'), ('Rick', 'Martinez')]
>>> firstnames = ['Mark', 'Melissa', 'Rick']
>>> lastnames = ['Watney', 'Lewis']
>>> myzip(firstnames, lastnames)
[('Mark', 'Watney'), ('Melissa', 'Lewis')]
"""
# Define function `myzip`:
# - takes two parameters `a: list`, `b: list`
# - pairs `a` elements with `b` elements in form of `list[tuple]`
# - first from `a` is paired with first from `b`, etc.
# - collect number of pairs equal to the count of shortest list
# Do not use built-in `zip()` function
# type: Callable[[list], int]
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Usecase AsTuple
# - Difficulty: easy
# - Lines: 2
# - Minutes: 2
# %% English
# 1. Define function `astuple`:
# - takes `data: dict`
# - returns tuple with `data` values
# 2. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj funkcję `astuple`:
# - przyjmuje `data: dict`
# - zwraca tuplę z wartościami z `data`
# 2. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from inspect import isfunction
>>> assert astuple is not Ellipsis, \
'Write solution inside `astuple` function'
>>> assert isfunction(astuple), \
'Object `astuple` must be a function'
>>> astuple({'a':1, 'b':2, 'c':3})
(1, 2, 3)
>>> astuple({'firstname':'Mark', 'lastname':'Watney'})
('Mark', 'Watney')
"""
# Define function `astuple`:
# - takes `data: list[int|float]`
# - returns tuple with min and max value from `data`
# Do not use built-in `min()` and `max()` functions
# type: Callable[[dict], tuple]
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Parameters BloodPressure
# - Difficulty: medium
# - Lines: 10
# - Minutes: 13
# %% English
# 1. Table contains Blood Pressure classification according to American Heart Association [1]
# 2. User inputs blood pressure: systolic and diastolic
# 3. User will not try to input invalid data
# 4. Print status of given blood pressure
# 5. If systolic and diastolic values are in different categories, assume worst case
# 6. Run doctests - all must succeed
# %% Polish
# 1. Tabela zawiera klasyfikację ciśnienia krwi wg American Heart Association [1]
# 2. Użytkownik wprowadza ciśnienie krwi: skurczowe i rozkurczowe
# 3. Użytkownik nie będzie próbował wprowadzać danych niepoprawnych
# 4. Wypisz status wprowadzonego ciśnienia krwi
# 5. Gdy wartości ciśnienia skurczowego i rozkurczowego należą do różnych kategorii, przyjmij gorszy przypadek
# 6. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `and`
# - `or`
# %% References
# [1] Whelton, Paul K. and et al.
# 2017 ACC/AHA/AAPA/ABC/ACPM/AGS/APhA/ASH/ASPC/NMA/PCNA Guideline
# for the Prevention, Detection, Evaluation, and Management of High
# Blood Pressure in Adults: Executive Summary: A Report of the American
# College of Cardiology/American Heart Association Task Force on Clinical
# Practice Guidelines. Journal of Hypertension. vol 71. pages 1269–1324.
# 2018. doi: 10.1161/HYP.0000000000000066
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> result = blood_pressure(0,0)
>>> assert result is not Ellipsis, \
'Assign your result to variable `result`'
>>> assert type(result) is str, \
'Variable `result` has invalid type, should be str'
>>> result in (STATUS_NORMAL, STATUS_ELEVATED, STATUS_HYPERTENSION_STAGE_1,
... STATUS_HYPERTENSION_STAGE_2, STATUS_HYPERTENSIVE_CRISIS)
True
>>> blood_pressure(115, 75)
'Normal'
>>> blood_pressure(125, 75)
'Elevated'
>>> blood_pressure(135, 85)
'Hypertension stage 1'
>>> blood_pressure(145, 95)
'Hypertension stage 2'
>>> blood_pressure(195, 135)
'Hypertensive Crisis'
>>> blood_pressure(119, 0)
'Normal'
>>> blood_pressure(120, 0)
'Elevated'
>>> blood_pressure(0, 79)
'Normal'
>>> blood_pressure(0, 80)
'Hypertension stage 1'
>>> blood_pressure(120, 80)
'Hypertension stage 1'
>>> blood_pressure(129, 0)
'Elevated'
>>> blood_pressure(130, 0)
'Hypertension stage 1'
>>> blood_pressure(0, 79)
'Normal'
>>> blood_pressure(0, 80)
'Hypertension stage 1'
>>> blood_pressure(130, 80)
'Hypertension stage 1'
>>> blood_pressure(139, 0)
'Hypertension stage 1'
>>> blood_pressure(140, 0)
'Hypertension stage 2'
>>> blood_pressure(0, 89)
'Hypertension stage 1'
>>> blood_pressure(0, 90)
'Hypertension stage 2'
>>> blood_pressure(140, 90)
'Hypertension stage 2'
>>> blood_pressure(180, 0)
'Hypertension stage 2'
>>> blood_pressure(181, 0)
'Hypertensive Crisis'
>>> blood_pressure(0, 120)
'Hypertension stage 2'
>>> blood_pressure(0, 121)
'Hypertensive Crisis'
>>> blood_pressure(181, 121)
'Hypertensive Crisis'
"""
STATUS_NORMAL = 'Normal'
STATUS_ELEVATED = 'Elevated'
STATUS_HYPERTENSION_STAGE_1 = 'Hypertension stage 1'
STATUS_HYPERTENSION_STAGE_2 = 'Hypertension stage 2'
STATUS_HYPERTENSIVE_CRISIS = 'Hypertensive Crisis'
# | Blood Pressure Category | Systolic [mm Hg] | Operator | Diastolic [mm Hg] |
# |-------------------------|------------------|----------|-------------------|
# | Normal | Less than 120 | and | Less than 80 |
# | Elevated | 120-129 | and | Less than 80 |
# | Hypertension stage 1 | 130-139 | or | 80-89 |
# | Hypertension stage 2 | 140 or higher | or | 90 or higher |
# | Hypertensive Crisis | Higher than 180 | and/or | Higher than 120 |
# User inputs blood pressure: systolic and diastolic
# User will not try to input invalid data
# Print status of given blood pressure
# If systolic and diastolic values are in different categories, assume worst case
# One of the STATUS_*
# type: Callable[[int,int], str]
def blood_pressure(systolic, diastolic):
return ...
# FIXME: Translate input data to English
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Arguments Clean
# - Difficulty: medium
# - Lines: 15
# - Minutes: 13
# %% English
# 1. Define function `clean`:
# - parameter `text: str` (required)
# - returns `str` with cleaned text
# 2. To clean text:
# - Normalize text
# - Remove unwanted whitespaces (eg. \n, \t, spaces, non-breaking spaces, multiple spaces)
# - Remove unwanted special characters (e.g. !, @, #, $, %, ^, &, *, +, =, _, ', ")
# - Remove unwanted fragments (eg. ul, ulica, os, osiedle, pl, plac, al, aleja)
# - Replace numbers (eg. 3, 2, 1, trzeciego, drugiego, pierwszego) with Roman numerals (III, II, I)
# - Format text (strip, capitalize first letter of each word)
# 3. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj funkcję `clean`:
# - parametr `text: str` (wymagany)
# - zwraca `str` z oczyszczonym tekstem
# 2. Aby oczyścić tekst:
# - Znormalizuj tekst
# - Usuń niechciane białe znaki (np. \n, \t, spacje, twarde space, wiele spacji)
# - Usuń niechciane znaki specjalne (np. !, @, #, $, %, ^, &, *, +, =, _, ', ")
# - Usuń niechciane fragmenty (np. ul, ulica, os, osiedle, pl, plac, al, aleja)
# - Zamień liczby (np. 3, 2, 1, trzeciego, drugiego, pierwszego) na liczby rzymskie (III, II, I)
# - Sformatuj tekst (strip, zacznij od wielkiej litery)
# 3. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from inspect import isfunction
>>> assert clean is not Ellipsis, \
'Write solution inside `clean` function'
>>> assert isfunction(clean), \
'Object `clean` must be a function'
>>> clean('ul.Mieszka II')
'Mieszka II'
>>> clean('UL. Zygmunta III WaZY')
'Zygmunta III Wazy'
>>> clean(' bolesława chrobrego ')
'Bolesława Chrobrego'
>>> clean('ul Jana III SobIESkiego')
'Jana III Sobieskiego'
>>> clean('\tul. Jana trzeciego Sobieskiego')
'Jana III Sobieskiego'
>>> clean('ulica Jana III Sobieskiego')
'Jana III Sobieskiego'
>>> clean('ULICA JANA III SOBIESKIEGO ')
'Jana III Sobieskiego'
>>> clean('ULICA JANA III SOBIeskieGO')
'Jana III Sobieskiego'
>>> clean(' Jana 3 Sobieskiego ')
'Jana III Sobieskiego'
"""
# Define function `clean`:
# - parameter `text: str` (required)
# - returns `str` with cleaned text
#
# To clean text:
# - Normalize text
# - Remove unwanted whitespaces (eg. \n, \t, spaces, non-breaking spaces, multiple spaces)
# - Remove unwanted special characters (e.g. !, @, #, $, %, ^, &, *, +, =, _, ', ")
# - Remove unwanted fragments (eg. ul, ulica, os, osiedle, pl, plac, al, aleja)
# - Replace numbers (eg. 3, 2, 1, trzeciego, drugiego, pierwszego) with Roman numerals (III, II, I)
# - Format text (strip, capitalize first letter of each word)
# type: Callable[[str], str]
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Function Arguments Num2Str
# - Difficulty: medium
# - Lines: 5
# - Minutes: 8
# %% English
# 1. Given is pilot's alphabet for numbers
# 2. Convert `DATA: dict[int, str]` to `data: dict[str,str]`
# (keys as `str`)
# 3. Define function `pilot_say` converting `int` or `float`
# to text form in Pilot's Speak
# 4. You cannot change `DATA`, but you can modify `data`
# 5. Run doctests - all must succeed
# %% Polish
# 1. Dany jest alfabet pilotów dla numerów
# 2. Przekonwertuj `DATA: dict[int, str]` na `data: dict[str,str]`
# (klucze jako `str`)
# 3. Zdefiniuj funkcję `pilot_say` konwertującą `int` lub `float`
# na formę tekstową w mowie pilotów
# 4. Nie możesz zmieniać `DATA`, ale możesz modyfikować `data`
# 5. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> from inspect import isfunction
>>> assert pilot_say is not Ellipsis, \
'Write solution inside `pilot_say` function'
>>> assert isfunction(pilot_say), \
'Object `pilot_say` must be a function'
>>> pilot_say(1)
'one'
>>> pilot_say(+1)
'one'
>>> pilot_say(-1)
'minus one'
>>> pilot_say(1+1)
'two'
>>> pilot_say(1-1)
'zero'
>>> pilot_say(1969)
'one niner six niner'
>>> pilot_say(31337)
'tree one tree tree seven'
>>> pilot_say(13.37)
'one tree and tree seven'
>>> pilot_say(31.337)
'tree one and tree tree seven'
>>> pilot_say(-1969)
'minus one niner six niner'
>>> pilot_say(-31.337)
'minus tree one and tree tree seven'
>>> pilot_say(-49.35)
'minus fower niner and tree fife'
>>> pilot_say(1.0)
'one and zero'
>>> pilot_say(1.)
'one and zero'
>>> pilot_say(123.)
'one two tree and zero'
>>> pilot_say(123.0)
'one two tree and zero'
>>> pilot_say(.44)
'zero and fower fower'
>>> pilot_say(1-)
Traceback (most recent call last):
SyntaxError: invalid syntax
"""
DATA = {
0: 'zero',
1: 'one',
2: 'two',
3: 'tree',
4: 'fower',
5: 'fife',
6: 'six',
7: 'seven',
8: 'ait',
9: 'niner',
}
# Given is pilot's alphabet for numbers
# Convert `DATA: dict[int, str]` to `data: dict[str,str]` (keys as `str`)
# Define function `pilot_say` converting `int` or `float`
# to text form in Pilot's Speak
# You cannot change `DATA`, but you can modify `data`
# type: Callable[[int|float], str]
...