Chapter 6: Using Functions and Modules
See previous articles:
Chapter 1: Initial Python
Chapter 2: Language Elements
Chapter 3: Branch Structure
Chapter 4: Loop Structure
Chapter 5: Constructing Program Logic
Or go to the column "Python Tutorial" to view
Resource directory: Code (6)
Article resource download: (1-15 chapters)
Link: https://pan.baidu.com/s/1Mh1knjT4Wwt__7A9eqHmng?pwd=t2j3
Extraction code: t2j3
Before explaining the content of this chapter, let's study a math problem first. Please tell how many sets of positive integer solutions the following equation has.
In fact, the above problem is equivalent to how many ways there are to divide 8 apples into four groups with at least one apple in each group. The answer to this question is imminent.
This value can be calculated with a Python program, the code is as follows.
"""
输入M和N计算C(M,N)
Version: 0.1
Author: 骆昊
"""
m = int(input('m = '))
n = int(input('n = '))
fm = 1
for num in range(1, m + 1):
fm *= num
fn = 1
for num in range(1, n + 1):
fn *= num
fm_n = 1
for num in range(1, m - n + 1):
fm_n *= num
print(fm // fn // fm_n)
What the function does
I don’t know if you have noticed that in the above code, we have done 3 times to find the factorial, such code is actually repeated code. Programming master Mr. Martin Fowler once said: " Code has many bad smells, and repetition is the worst one! " To write high-quality code, the first thing to solve is the problem of repeated code. For the above code, we can encapsulate the function of calculating factorial into a function module called "function". Where we need to calculate factorial, we only need to "call" this "function".
define function
In Python, def
keywords can be used to define functions. Like variables, each function also has a famous name, and the naming rules are consistent with the naming rules of variables. The parameters passed to the function can be placed in the parentheses after the function name, which is very similar to the function in mathematics. The parameters of the function in the program are equivalent to the arguments of the function in mathematics, and after the function is executed, we can Return a value through return
the keyword, which is equivalent to the dependent variable of the function in mathematics.
After understanding how to define functions, we can refactor the above code. The so-called refactoring is to adjust the structure of the code without affecting the code execution results. The refactored code is as follows.
"""
输入M和N计算C(M,N)
Version: 0.1
Author: 骆昊
"""
def fac(num):
"""求阶乘"""
result = 1
for n in range(1, num + 1):
result *= n
return result
m = int(input('m = '))
n = int(input('n = '))
# 当需要计算阶乘的时候不用再写循环求阶乘而是直接调用已经定义好的函数
print(fac(m) // fac(n) // fac(m - n))
Explanation:
math
In fact, there is already a function named function in the Python modulefactorial
that implements the factorial operation. In fact, you don’t need to define the function yourself to calculate the factorial. In the following example, the functions we are talking about have already been implemented in the Python standard library. We implement them again here to explain the definition and use of functions. In actual development, it is not recommended to do such low-level repetitive work .
function parameters
A function is a "building block" of code supported by most programming languages, but there are still many differences between functions in Python and functions in other languages. deal with. In Python, the parameters of functions can have default values, and also support the use of variable parameters, so Python does not need to support function overloading like other languages, because when we define a function, we can make it have many different How to use, the following are two small examples.
from random import randint
def roll_dice(n=2):
"""摇色子"""
total = 0
for _ in range(n):
total += randint(1, 6)
return total
def add(a=0, b=0, c=0):
"""三个数相加"""
return a + b + c
# 如果没有指定参数那么使用默认值摇两颗色子
print(roll_dice())
# 摇三颗色子
print(roll_dice(3))
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
# 传递参数时可以不按照设定的顺序进行传递
print(add(c=50, a=100, b=200))
We have set default values for the parameters of the above two functions, which means that if the value of the corresponding parameter is not passed in when calling the function, the default value of the parameter will be used, so in the above code we Functions can be called in various ways add
, which is consistent with the effect of function overloading in many other languages.
In fact, there is a better implementation of the above add
function, because we may add 0 or more parameters, and the specific number of parameters is determined by the caller. As the designer of the function, we are Know nothing, so when the number of parameters is uncertain, we can use variable parameters, the code is as follows.
# 在参数名前面的*表示args是一个可变参数
def add(*args):
total = 0
for val in args:
total += val
return total
# 在调用add函数时可以传入0个或多个参数
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
print(add(1, 3, 5, 7, 9))
Manage functions with modules
For any programming language, naming identifiers such as variables and functions is a headache, because we will encounter the embarrassing situation of naming conflicts. The simplest scenario is to define two functions with the same name in the same .py file. Since Python does not have the concept of function overloading, the latter definition will override the previous definition, which means that two functions with the same name are actually only One exists.
def foo():
print('hello, world!')
def foo():
print('goodbye, world!')
# 下面的代码会输出什么呢?
foo()
Of course, we can easily avoid the above situation, but if the project is developed by a multi-person team, there may be multiple programmers in the team who have defined the function named, so how to solve this naming foo
conflict Woolen cloth? The answer is actually very simple. Each file in Python represents a module. We can have functions with the same name in different modules. When using a function, we can import the specified module by keyword to distinguish between the modules to be used import
. Which module is foo
the function in, the code is as follows.
module1.py
def foo():
print('hello, world!')
module2.py
def foo():
print('goodbye, world!')
test.py
from module1 import foo
# 输出hello, world!
foo()
from module2 import foo
# 输出goodbye, world!
foo()
You can also distinguish which foo
function to use as shown below.
test.py
import module1 as m1
import module2 as m2
m1.foo()
m2.foo()
But if the code is written as follows, then the last imported one is called in the program foo
, because the later imported foo overwrites the previous imported one foo
.
test.py
from module1 import foo
from module2 import foo
# 输出goodbye, world!
foo()
test.py
from module2 import foo
from module1 import foo
# 输出hello, world!
foo()
It should be noted that if the module we import has executable code in addition to defining functions, then the Python interpreter will execute these codes when importing this module. In fact, we may not want this, so if we are in the module The execution code is written in , it is best to put these execution codes into the conditions shown below, so that unless the module is run directly, the code under the if condition will not be executed, because only the name of the directly executed module It is "__main__".
module3.py
def foo():
pass
def bar():
pass
# __name__是Python中一个隐含的变量它代表了模块的名字
# 只有被Python解释器直接执行的模块的名字才是__main__
if __name__ == '__main__':
print('call foo()')
foo()
print('call bar()')
bar()
test.py
import module3
# 导入module3时 不会执行模块中if条件成立时的代码 因为模块的名字是module3而不是__main__
practise
Exercise 1: Realize the function of calculating the greatest common divisor and least common multiple.
Reference answer:
def gcd(x, y):
"""求最大公约数"""
(x, y) = (y, x) if x > y else (x, y)
for factor in range(x, 0, -1):
if x % factor == 0 and y % factor == 0:
return factor
def lcm(x, y):
"""求最小公倍数"""
return x * y // gcd(x, y)
Exercise 2: Realize the function of judging whether a number is a palindrome.
Reference answer:
def is_palindrome(num):
"""判断一个数是不是回文数"""
temp = num
total = 0
while temp > 0:
total = total * 10 + temp % 10
temp //= 10
return total == num
Exercise 3: Implement a function to judge whether a number is prime or not.
Reference answer:
def is_prime(num):
"""判断一个数是不是素数"""
for factor in range(2, int(num ** 0.5) + 1):
if num % factor == 0:
return False
return True if num != 1 else False
Exercise 4: Write a program to judge whether the input positive integer is a palindromic prime number.
Reference answer:
if __name__ == '__main__':
num = int(input('请输入正整数: '))
if is_palindrome(num) and is_prime(num):
print('%d是回文素数' % num)
Note : As can be seen from the above program, when we extract recurring and relatively independent functions in the code into functions , we can use these functions in combination to solve more complex problems, which is why we define and use function for a very important reason.
variable scope
Finally, let's discuss the scope of variables in Python.
def foo():
b = 'hello'
# Python中可以在函数内部再定义函数
def bar():
c = True
print(a)
print(b)
print(c)
bar()
# print(c) # NameError: name 'c' is not defined
if __name__ == '__main__':
a = 100
# print(b) # NameError: name 'b' is not defined
foo()
The above code can be executed smoothly and print out 100, hello and True, but we noticed that there are no two variables bar
defined inside the function , so where does the sum come from. We defined a variable in the branch of the above code , which is a global variable (global variable) and belongs to the global scope because it is not defined in any function. In the above function, we defined a variable , which is a local variable (local variable) defined in the function, which belongs to the local scope and cannot be accessed outside the function; but for the function inside the function , the variable It belongs to the nested scope, and we can access it in the function. Variables in functions belong to local scope and cannot be accessed outside the function. In fact, when Python looks for a variable, it will search in the order of "local scope", "nested scope", "global scope" and "built-in scope". The first three we have seen in the above code Arrived, the so-called "built-in scope" is the built-in identifiers of Python, we have used before , ,, etc. belong to the built-in scope.a
b
a
b
if
a
foo
b
foo
foo
bar
b
bar
bar
c
bar
input
print
int
Look at the following code again, we hope to modify a
the value of the global variable through a function call, but in fact the following code cannot be done.
def foo():
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 100
After calling foo
the function, a
the value we found is still 100. This is because when we foo
write in the function a = 200
, we redefine a local variable named , which is not the same variable a
as the global scope , because the local a
Scope now has its own variable a
, so foo
the function no longer searches the global scope a
. If we want to foo
modify the global scope in the function a
, the code is as follows.
def foo():
global a
a = 200
print(a) # 200
if __name__ == '__main__':
a = 100
foo()
print(a) # 200
We can use global
keywords to indicate that foo
the variables in the function a
come from the global scope. If there is no global scope a
, then the following line of code will define the variable a
and put it in the global scope. Similarly, if we want the function inside the function to be able to modify variables in the nested scope, we can use nonlocal
keywords to indicate that the variable comes from the nested scope, please try it yourself.
In actual development, we should minimize the use of global variables, because the scope and influence of global variables are too wide, and unexpected modification and use may occur. In addition, global variables have a longer lifetime than local variables. The life cycle may cause the memory occupied by the object to be unable to be garbage collected for a long time . In fact, reducing the use of global variables is also an important measure to reduce the coupling between codes, and it is also a practice of Dimiter's law . Reducing the use of global variables means that we should try to keep the scope of variables inside the function, but if we want to extend the life cycle of a local variable so that its value can still be used after the function call that defines it ends , you need to use closures at this time , which we will explain in the follow-up content.
Explanation: Many people often confuse "closure" and "anonymous function" , but in fact they are not the same thing. If you want to understand this concept, you can read Wikipedia 's explanation or Zhihu's discussion on this concept .
Having said so much, the conclusion is actually very simple. From now on, we can write Python code according to the following format. This little improvement is actually a huge step on the basis of our understanding of functions and scope.
def main():
# Todo: Add your code here
pass
if __name__ == '__main__':
main()