Chapter 6: Using Functions and Modules

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.

insert image description here

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.

insert image description here

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, defkeywords 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 returnthe 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 module factorialthat 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 addfunction, 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 fooconflict 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 foothe 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 foofunction 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 bardefined 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.ababifafoobfoofoobarbbarbarcbarinputprintint

Look at the following code again, we hope to modify athe 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 foothe function, athe value we found is still 100. This is because when we foowrite in the function a = 200, we redefine a local variable named , which is not the same variable aas the global scope , because the local aScope now has its own variable a, so foothe function no longer searches the global scope a. If we want to foomodify 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 globalkeywords to indicate that foothe variables in the function acome from the global scope. If there is no global scope a, then the following line of code will define the variable aand 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 nonlocalkeywords 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()

Guess you like

Origin blog.csdn.net/xyx2023/article/details/129635113