Python learning road 7-function

This series is a compilation of notes for the introductory book "Python Programming: From Getting Started to Practice", which belongs to the primary content. The title sequence follows the title of the book.
This chapter mainly introduces the operation of functions in Python, including the concept, definition, how to pass parameters, etc. of functions, and finally the concept of a small part of modules.

define function

general function

A function is a named block of code that is a fixed sequence of code that does a specific job. If the same or similar code block appears multiple times in the program, this code should be extracted, written as a function, and then called multiple times. By writing functions you avoid duplication of work and make programs easier to write, read, test, and fix. Please name the function with a descriptive function name to roughly indicate what the function does, so it's easy to understand even without comments. Function names should be limited to lowercase letters and underscores as much as possible. The following are the two most basic functions, parameterized and parameterless:

# 定义无参函数
def greet_user1():
    """显示简单的问候语"""
    print("Hello!")

# 定义有参函数
def greet_user2(username):
    """显示简单的问候语"""
    print("Hello, " + username.title() + "!")

# 调用函数
greet_user1()
greet_user2("jesse")

# 结果:
Hello!
Hello, Jesse!

Before calling a function, you must define a function! That is, the definition part of the function must come before the calling statement.
The triple-quoted strings in the above code are called docstrings , and they can be used both as code comments and to automatically generate documentation about functions in the program.

The two concepts of actual parameters and formal parameters
are often confused. The parameters in the function definition are called formal parameters. For example, the parameters in the above function greet_user2(username)are usernameformal parameters; the parameters passed to the function are called actual parameters, such as greet_user2("jesse")when they are called "jesse".

empty function

If you want to define a function that does nothing, you can use the passstatement

def do_nothing():
    pass

If you want to make the program run, but do not write this function for the time being, you can use a passstatement. Used here passas a placeholder.

pass parameters

Positional parameter (required parameter)

This is to require the order of the actual parameters to be the same as the order of the formal parameters.

# 代码:
def describe_pet(animal_type, pet_name):
    """显示宠物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")

describe_pet("hamster", "harry")
describe_pet("dog", "willie")

# 结果:
I have a hamster.
My hamster's name is Harry.

I have a dog.
My dog's name is Willie.

For positional parameters, you should pay attention to the order in which the actual parameters are passed. If the order is not correct, the result will be unexpected: an error may be reported. If no error is reported, the meaning of the function may change.

# 代码:
describe_pet("willie", "dog")

# 结果:
I have a willie.           # 尴尬
My willie's name is Dog.

Keyword arguments (when passing arguments)

If the function has too many formal parameters, it is difficult to remember what the parameters of each position are used for. If the actual parameters are passed in the form of key-value pairs , this problem can be solved easily, which is the keyword parameter. When passing parameters, directly associate the formal parameters with the actual parameters, so that you don't need to care about the position of the actual parameters. Still taking the above code as an example, the function definition remains unchanged:

# 代码:
describe_pet(animal_type="hamster", pet_name="harry")
describe_pet(pet_name="harry", animal_type="hamster")

# 结果:
I have a hamster.
My hamster's name is Harry.

I have a hamster.
My hamster's name is Harry.

Note that this is a way to pass parameters ! Use when calling a function !

Default parameters (when defining a function, formal parameters)

When writing a function, you can specify a default value for each formal parameter. After specifying a default value for the formal parameter, you can omit the corresponding actual parameter when calling the function. Using default values ​​simplifies function calls and clearly indicates typical usage of the function. For example , describe_pet()if the above function animal_typespecifies default values ​​for the formal parameters “dog”, it can be seen that this function is mainly used to describe pets such as dogs.

# 代码:
def describe_pet(pet_name, animal_type="dog"):
    """显示宠物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")


describe_pet(pet_name="willie")
describe_pet("happy")
describe_pet("lili", "cat")

# 结果:
I have a dog.
My dog's name is Willie.

I have a dog.
My dog's name is Happy.

I have a cat.
My cat's name is Lili.

When a function is called, if an argument is provided for a formal parameter, Python will use the specified actual parameter; otherwise, the default value of the formal parameter will be used.
Note : Default parameters are used when the function is defined ! When defining a function, a parameter with a default value must follow a parameter without a default value!

One more thing worth noting: the default parameter must point to an immutable object! Please see the following code:

# 代码:
def add_end(temp=[]):
    """在传入的列表最后添加“end”"""
    temp.append("end")
    return temp


print(add_end([1, 2, 3]))
print(add_end(["a", "b", "c"]))
print(add_end())
print(add_end())
print(add_end())

# 结果:
[1, 2, 3, 'end']
['a', 'b', 'c', 'end']
['end']
['end', 'end']
['end', 'end', 'end']

When passing parameters to this function, the result is correct, and when no parameters are passed and the first call, the returned result is also correct, however, when no parameters are passed and the second and third calls are made, the result becomes a problem. This is because Python calculates the value of the default parameter when the function is defined. As long as the formal parameter does not point to a new value, it will always point to the default value, but if the default value is a mutable object, then The above will occur.
To fix the above example, you can use Nonean strimmutable object like , . as follows:

def add_end(temp=None):
    """在传入的列表最后添加“end”"""
    if temp is None:
        temp = []
    temp.append("end")
    return temp

print(add_end())
print(add_end())

# 结果:
['end']
['end']

Supplement – ​​Reasons for designing immutable objects :
①Once an object is created, it cannot be modified, which can reduce errors caused by modifying data;
②Because the object is unmodifiable, it does not need to be locked in a multi-tasking environment, and reading at the same time will not make mistakes. Therefore, when we design an object, if it can be designed as an immutable object, it is designed as an immutable object.

return value

return simple value

A function doesn't always display output directly, it can process some data and return a value or set of values. In Python functions, use returnstatements to return values. The following is an example of a function with optional parameters and a return value:

# 代码:
def get_formatted_name(first_name, last_name, middel_name=""):
    """返回标准格式的姓名"""
    if middel_name:
        full_name = first_name + " " + middel_name + " " + last_name
    else:
        full_name = first_name + " " + last_name

    return full_name.title()


musician = get_formatted_name("jimi", "hendrix")
print(musician)

musician = get_formatted_name("john", "hooker", "lee")
print(musician)

# 结果:
Jimi Hendrix
John Lee Hooker

return dictionary

Python functions can return any type of value, including complex data structures such as lists and dictionaries.

# 代码:
def build_person(first_name, las_name, age=""):
    """返回一个字典,其中包含一个人的信息"""
    person = {"first": first_name, "last": las_name}
    if age:
        person["age"] = age
    return person


musician = build_person("jimi", "hendrix", age=27)
print(musician)

# 结果:
{'first': 'jimi', 'last': 'hendrix', 'age': 27}

return multiple values

returnMultiple values ​​can be returned by separating multiple values ​​with commas after the statement:

# 代码:
def return_mult():
    return 1, 2

a, b = return_mult()
print("a = " + str(a) + "\nb = " + str(b))

# 结果:
a = 1
b = 2

But in fact, this is an illusion. In fact, the function returns a tuple (Tuple), but the tuple is finally unpacked, and then athe bparallel assignment is performed.

# 代码:
print(return_mult())

# 结果:
(1, 2)

If the function returns multiple values, some of which are not desired, the values ​​in those positions can _be received with underscores:

def return_mult():
    return 1, 2, 3

a, _, _ = return_mult()

pass list

Pass the list to a function, and the function can directly access its contents or modify it. Manipulating lists with functions can be more efficient.
The following code is a print program that transfers unprinted designs to another list after printing, no function is used in this code:

# 代码:
# 未打印列表
unprinted_designs = ["iphone case", "robot pendant", "dodecahedron"]
completed_models = []

# 模拟打印过程,知道没有未打印的设计为止,并将已打印的设计移动到“完成列表”
while unprinted_designs:
    current_design = unprinted_designs.pop()

    # 模拟打印过程
    print("Printing model: " + current_design)
    completed_models.append(current_design)

print("\nThe following models have been printed:")
for completed_model in completed_models:
    print(completed_model)

# 结果:
Printing model: dodecahedron
Printing model: robot pendant
Printing model: iphone case

The following models have been printed:
dodecahedron
robot pendant
iphone case

Now restructure this code with two functions:

# 两个函数:
def print_models(unprinted_designs, completed_models):
    """模拟打印过程,知道没有未打印的设计为止,并将已打印的设计移动到“完成列表”"""
    while unprinted_designs:
        current_design = unprinted_designs.pop()

        # 模拟打印过程
        print("Printing model: " + current_design)
        completed_models.append(current_design)


def show_completed_models(completed_models):
    print("\nThe following models have been printed:")
    for completed_model in completed_models:
        print(completed_model)

# 主程序代码:
unprinted_designs = ["iphone case", "robot pendant", "dodecahedron"]
completed_models = []

print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)

As can be seen from the above code, after using the function, the main program becomes just four lines.
Code with functions is more readable and easier to maintain than code without functions.
When writing functions, try to only be responsible for one function per function. If a function is responsible for too many functions, it should be divided into multiple functions. At the same time, a function can call another function; a function can also define a function!

Forbidden function to modify the list :
Sometimes it is necessary to prohibit the function to modify the list. Take the above code as an example, the print_models()function clears the unprinted list after the execution is completed unprinted_design, but sometimes we do not want this list to be cleared, but keep it for the record. To work around this, you can pass a copy to the function instead of the original, like this:

# 不用改变函数定义,在函数调用时使用切片操作:
print_models(unprinted_designs[:], completed_models)

If you look at it from a C/C++ point of view (haven't studied the underlying code of Python, this is just a guess), the actual parameter unprinted_designsis a pointer, and when it is passed to the function, the formal parameter gets a copy of this variable, and the formal parameter also points to That area in memory, so it can be modified directly. When using a slice to pass a copy, Python first copies unprinted_designsthe data pointed to by the actual parameter in memory, assigns the address of this piece of data to a temporary variable, and then passes the temporary variable to the formal parameter.

Pass any number of arguments

Combining positional arguments (required arguments) with any number of arguments (*args)

Sometimes you don't know how many parameters to pass to the function, such as making pizza, and you don't know how many toppings the customer wants. In this case, use the parameter with an asterisk *to define the function:

# 代码:
def make_pizza(*toppings):
    """打印顾客点的所有配料"""
    print(toppings)

make_pizza()    # 不传参数
make_pizza("pepperoni")
make_pizza("mushrooms", "green peppers", "extra cheese")

# 结果:
()
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')

As can be seen from the results, when passing in a value as a variable parameter, Python encapsulates the value into a tuple, even if only one value is passed in.

Supplement : Multiple parameters are in a list. If one element is passed element by element, the code will be ugly. You can use the following methods to pass parameters. Take the above make_pizza()function as an example:

toppings = ["mushrooms", "green peppers", "extra cheese"]
make_pizza(*toppings)    # 这里是在执行函数,而不是在定义函数!

In the "Arbitrary Keyword Arguments" section that follows, values ​​can also be passed in this way, but with double asterisks **.

Note : If you want a function to accept arguments of different types, you must put variadic arguments last, because Python matches positional and keyword arguments first, and then wraps the remaining arguments into the last varargs.

# 代码:
def make_pizza(size, *toppings):
    """概述要制作的披萨"""
    print("\nMaking a " + str(size) + "-inch pizza with the following toppings:")
    for topping in toppings:
        print("- " + topping)

make_pizza(16, "pepperoni")
make_pizza(12, "mushrooms", "green peppers", "extra cheese")

# 结果:
Making a 16-inch pizza with the following toppings:
- pepperoni

Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese

Use any number of keyword arguments (**kw)

Sometimes you need to pass in any number of parameters, and you also need to know what these parameters are used for. At this time, the function needs to be able to accept any number of keyword parameters. Here we use double asterisks **to achieve:

# 代码:
def build_profile(first, last, **user_info):
    print(user_info)

    """创建一个字典,其中包含我们知道的有关用户的一切"""
    profile = {}
    profile["first_name"] = first
    profile["last_name"] = last
    for key, value in user_info.items():
        profile[key] = value
    return profile

user_profile = build_profile("albert", "einstein", location="princeton", field="physics")
print(user_profile)

# 结果:
{'location': 'princeton', 'field': 'physics'}
{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': physics'}

As can be seen from the above results, Python encapsulates arbitrary keyword arguments into a dictionary. Note here, too, that formal parameters indicating any keyword arguments must be placed last!

Distinction - named keyword parameters (also called named parameters) :
the above code can pass any number of keyword parameters, but sometimes it is necessary to limit the incoming keyword parameters, such as the above build_profile()function in addition to the incoming firstand lastthese two required parameters , you must and can only pass agein countrythese two parameters (one more, one less), you need to use named keyword parameters, which use an asterisk to separate required parameters and named keyword parameters, as follows:

# 代码:
# 星号后面的为命名关键字参数
def build_profile(first, last, *, age, country="China"):
    """创建一个字典,其中包含我们知道的有关用户的一切"""
    profile = {}
    profile["first_name"] = first
    profile["last_name"] = last
    profile["age"] = age
    profile["country"] = country
    return profile


print(build_profile("albert", "einstein", country="USA", age=20))
print(build_profile("albert", "einstein", age=20))
print(build_profile(age=20, country="USA", first="albert", last="einstein"))
# print(build_profile("albert", "einstein"))

# 结果:
# 如果不看最后一个print(),则代码的执行结果如下:
{'first_name': 'albert', 'last_name': 'einstein', 'age': 20, 'country': 'USA'}
{'first_name': 'albert', 'last_name': 'einstein', 'age': 20, 'country': 'China'}
{'first_name': 'albert', 'last_name': 'einstein', 'age': 20, 'country': 'USA'}

# 如果将最后一个print()的注释去掉,则代码会报错

From the above results, it can be seen that each named keyword parameter must be assigned a value, and there can be a default value. If there is a default value, no assignment is required; the order of named keywords can be exchanged, and if you want to exchange the order with the previous mandatory parameters , you must use keyword arguments to pass arguments.

Why there are named keyword parameters :
(Answer from online search, I personally think that such parameters can be replaced by positional parameters) Named parameters can be used in conjunction with default parameters to simplify the code. For example, when writing a class constructor, there are 10 parameters. , 8 have reasonable default values, then these 8 can be defined as named keyword parameters, and the first two are positional parameters that must be assigned. In this way, when the object is generated later, if you want to replace the default value:
① Either replace the default value for the next 8 parameters in order (C++ practice);
② Either use the keyword parameter pass-by-value method to pass the value to these 8 keywords. Assign values ​​sequentially (Python approach);
③ or mix ① and ②, but it is easy to confuse. (That is, all required parameters are used, the first part is assigned in order, and the latter part is assigned with keyword parameters)

Some thoughts : But if the author writes the code by himself, for the time being, he prefers to use all required parameters with default values, that is, the following definition form:

def func(a, b, c="test1", d="test2", e="test3", f="test4", g="test5"):
    pass

instead of the following form:

def func(a, b, *, c="test1", d="test2", e="test3", f="test4", g="test5"):
    pass

Maybe the author is ignorant and has not yet grasped the essence of this method.
However, the above is the case without variable parameters, if the function is defined in the following form:

def func(a, b="test", c="test2", *args):
    pass

An error will be reported when called in the following form:

func("test1", c="test3", b="test2", "test4")

# 结果:
SyntaxError: positional argument follows keyword argument

It can be seen that Python will test4interpret it as a positional parameter here, but I want to use it as a variable parameter. Therefore, the author speculates that it is better to use named keyword parameters in the following situations:
there are a large number of required parameters (the default values ​​of some parameters do not change frequently), followed by variable parameters. It is easy to remember the position. If you do not use named parameters, it will be wrong to call the function according to the above keyword method. Therefore, at this time, if these mandatory parameters with reasonable default values ​​are changed to named keyword parameters, you can use keyword parameters out of order. pass value. But if there are no variable parameters, I still prefer to use the required parameters with default values.

One more thing worth noting : Named keyword arguments can be mixed with variadic arguments (*args), in which case the syntax is as follows:

def func(a, b, *agrs, c, d):
    pass

Here c, dit is a named keyword parameter, and it is not necessary to add a single asterisk to distinguish it. However, if it is mixed with a variable number of keyword parameters (**kw), the named keyword cannot be before the variable number of keyword parameters. , that is, the following function definition form does not exist :

def func(a, b, **kw, c, d):
    pass

If defined in this way, Pycharm will be marked in red (other IDEs have not used it, I don't know if it will prompt).

To sum up : There are five parameter types in Python, namely mandatory parameters (positional parameters), default parameters (parameters with default values), variable parameters (*args), named keyword parameters and keyword parameters ( Variable number, **kw), these five can be mixed at the same time, but must follow the following order:
(from left to right) mandatory parameters, default parameters, variable parameters, named keyword parameters and keyword parameters . Here are a few examples of mixing these two parameters:

def func1(a, b, *, c, d, **kw):
    """
    a, b 为必选参数
    c, d 为命名关键字参数
    kw 为关键字参数,可包含多对
    """
    pass


def func2(a, b="test", *args, c, d="test2", **kw):
    """
    :param a: 必选参数
    :param b: 带默认值的必选参数
    :param args: 可变参数
    :param c: 命名关键字参数
    :param d: 带默认值的命名关键字参数
    :param kw: 关键字参数,可包含多对 
    """
    pass

Commonly used functions that contain any number of keywords and do not distinguish between parameter types are defined as follows :

def func(*args, **kw):
    pass

def func(*args, **kwargs):
    pass

Store functions in modules

In python, a .pyfile is a module. The biggest advantage of using modules is to improve the maintainability of the code. Second, the code doesn't have to be written from scratch. After a module is written, it can be called elsewhere. Again, function name and variable name conflicts can be avoided, and different modules can have the same function name and variable name.

import the entire module

To make a function importable, you must first create a module. Take the above make_pizza()function as an example, delete the rest of the code, keep only this function, and then create a making_pizzas.pyfile in the current directory, and execute the following code to import the entire module:

# making_pizzas.py文件:
import pizza

pizza.make_pizza(12, "mushromms", "green peppers", "extra cheese")
pizza.make_pizza(16, "pepperoni")

# 结果:
Making a 12-inch pizza with the following toppings:
- mushromms
- green peppers
- extra cheese

Making a 16-inch pizza with the following toppings:
- pepperoni

When importing a module this way, the function is called as follows:

module_name.function_name()

Import a specific function in a module

The syntax structure is:

# 导入一个函数
from module_name import function_name

# 导入多个函数,逗号分隔
from module_name import func1, func2, func3

# 以此方式导入模块式,直接以函数名调用函数,前面不用加模块名

Still taking the above pizza.pyexample:

from pizza import make_pizza

make_pizza(12, "mushromms", "green peppers", "extra cheese")
make_pizza(16, "pepperoni")

Module supplement

Alias :
When the function name conflicts, or the function name and module name are too long, you can take a short name, similar to "nickname", take the above code as an example:

# 函数取别名
from pizza import make_pizza as mp

mp(12, "mushromms", "green peppers", "extra cheese")
mp(16, "pepperoni")

# -------------------- 另一个文件 ------------------------------
# 模块取别名
import pizza as p
p.make_pizza(12, "mushromms", "green peppers", "extra cheese")
p.make_pizza(16, "pepperoni")

Import all functions in a module :
For example import pizzaall functions in a module:

from pizza import *

make_pizza(12, "mushromms", "green peppers", "extra cheese")
make_pizza(16, "pepperoni")

However, when using large modules that you did not write yourself, it is best not to use this import method, because if there are functions or variables in the module with the same names as the functions or variables you wrote yourself, the result will be problematic. So, the general practice is to either import only the functions you need, or import the entire module and use the period notation.

Package :
A package in Python is a folder, but this folder must contain __init__.pya file named (with double underscores before and after), multiple modules can be placed in the package, and the organization structure is similar to that of a Java package.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325657970&siteId=291194637