-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path12_functions_tutorial.py
More file actions
207 lines (153 loc) · 5.07 KB
/
12_functions_tutorial.py
File metadata and controls
207 lines (153 loc) · 5.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# 1. Basic function definition
def greet():
print("Hello!")
greet() # Function call
# 2. Function with parameters
def greet_person(name):
print(f"Hello, {name}!")
greet_person("Pavel")
# 3. Function with multiple parameters
def add(a, b):
result = a + b
print(f"{a} + {b} = {result}")
add(5, 3)
# 4. Returning value from function
def multiply(a, b):
return a * b
result = multiply(4, 5)
print(f"Multiplication result: {result}")
# 5. Returning multiple values (actually returns a tuple)
def get_min_max(numbers):
return min(numbers), max(numbers)
minimum, maximum = get_min_max([1, 5, 3, 9, 2])
print(f"Minimum: {minimum}, Maximum: {maximum}")
# 6. Default parameters
def greet(name="Guest", greeting="Hello"):
print(f"{greeting}, {name}!")
greet() # Hello, Guest!
greet("Pavel") # Hello, Pavel!
greet("Pavel", "Hi") # Hi, Pavel!
# 7. Keyword arguments
def create_profile(name, age, city):
print(f"Name: {name}, Age: {age}, City: {city}")
# Positional arguments
create_profile("Pavel", 25, "Moscow")
# Keyword arguments (order doesn't matter!)
create_profile(age=25, name="Pavel", city="Moscow")
create_profile(city="Moscow", name="Pavel", age=25)
# Mixed variant (positional must be BEFORE keyword)
create_profile("Pavel", city="Moscow", age=25)
# 8. Positional-only parameters (Python 3.8+)
# Parameters before / can only be positional
def divide(a, b, /):
return a / b
result = divide(10, 2) # OK
# result = divide(a=10, b=2) # TypeError
# 9. Keyword-only parameters
# Parameters after * can only be keyword
def create_user(*, name, age, email):
print(f"Name: {name}, Age: {age}, Email: {email}")
create_user(name="Pavel", age=25, email="pavel@example.com") # OK
# create_user("Pavel", 25, "pavel@example.com") # TypeError
# 10. Combining positional, standard and keyword
def complex_function(pos_only, /, standard, *, keyword_only):
print(f"pos_only={pos_only}, standard={standard}, keyword_only={keyword_only}")
complex_function(1, 2, keyword_only=3) # OK
complex_function(1, standard=2, keyword_only=3) # OK
# complex_function(pos_only=1, standard=2, keyword_only=3) # TypeError
# 11. Docstrings (function documentation)
def calculate_area(width, height):
"""
Calculates the area of a rectangle.
Args:
width: rectangle width
height: rectangle height
Returns:
Rectangle area
"""
return width * height
print(calculate_area.__doc__) # Print documentation
help(calculate_area) # Built-in help
# 12. Functions as first-class objects
# Functions can be assigned to variables
def say_hello():
return "Hello!"
greeting = say_hello
print(greeting()) # Hello!
# 13. Functions as arguments to other functions
def apply_operation(x, y, operation):
return operation(x, y)
def add(a, b):
return a + b
def multiply(a, b):
return a * b
result = apply_operation(5, 3, add)
print(f"Result add: {result}")
result = apply_operation(5, 3, multiply)
print(f"Result multiply: {result}")
# 14. Local and global variables
global_var = "I'm global"
def test_scope():
local_var = "I'm local"
print(f"Inside function: {global_var}")
print(f"Inside function: {local_var}")
test_scope()
print(f"Outside function: {global_var}")
# print(local_var) # NameError: name 'local_var' is not defined
# 15. Modifying global variables
counter = 0
def increment():
global counter # Without this there will be an error
counter += 1
increment()
increment()
print(f"Counter: {counter}") # 2
# 16. Nonlocal (for nested functions)
def outer():
count = 0
def inner():
nonlocal count # Access variable from outer function
count += 1
return count
print(inner()) # 1
print(inner()) # 2
outer()
# 17. Recursion (function calls itself)
def factorial(n):
if n == 0 or n == 1:
return 1
else:
return n * factorial(n - 1)
print(f"5! = {factorial(5)}") # 120
# Recursion: Fibonacci
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(f"Fibonacci(7) = {fibonacci(7)}") # 13
# 18. Type annotations (type hints) - Python 3.5+
def greet(name: str) -> str:
return f"Hello, {name}!"
def add(a: int, b: int) -> int:
return a + b
# Note: type hints are not checked at runtime!
# They are used for documentation and static analysis (mypy, PyCharm)
# 19. Pass by value vs by reference
# Immutable objects (int, str, tuple) - by value
def change_number(x):
x = 100 # Doesn't affect external variable
num = 42
change_number(num)
print(f"num = {num}") # 42 (not changed)
# Mutable objects (list, dict) - by reference
def change_list(lst):
lst.append(4) # Modifies the original list!
numbers = [1, 2, 3]
change_list(numbers)
print(f"numbers = {numbers}") # [1, 2, 3, 4] (changed!)
# 20. Best practices
# - Function should do one thing (single responsibility principle)
# - Function name should be a verb (get_user, calculate_total)
# - Avoid modifying global variables
# - Use docstrings for documentation
# - Functions should be short (usually < 20 lines)