Python learning -- 2.8 functions

Call functions

Python has a lot of built-in useful functions that we can call directly.
Call the abs function:

>>> abs(100)
100
>>> abs(-20)
20
>>> abs(12.34)
12.34

Python's built-in common functions also include data type conversion functions, such as the int() function, which can convert other data types to integers:

>>> int('123')
123
>>> int(12.34)
12
>>> float('12.34')
12.34
>>> str(1.23)
'1.23'
>>> str(100)
'100'
>>> bool(1)
True
>>> bool('')
False

The function name is actually a reference to a function object. It is completely possible to assign the function name to a variable, which is equivalent to giving the function an "alias":

>>> a = abs # 变量a指向abs函数
>>> a(-1) # 所以也可以通过a调用abs函数
1

define function

In Python, to define a function, use the def statement, write the function name, parentheses, parameters in parentheses and colon: in turn, and then write the function body in an indented block, and the return value of the function is returned with the return statement.
Please note that when the statement inside the function body is executed, once the return is executed, the function is executed and the result is returned. Therefore, very complex logic can be implemented inside the function through conditional judgment and looping.
If there is no return statement, the function will return the result after execution, but the result is None. return None can be shortened to return

def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x

If you have saved the function definition of my_abs() as the test_1.py file, then you can start the Python interpreter in the current directory of the file, and use from test_1 import my_abs to import the my_abs() function, note that test_1 is the file name (without .py extension)

from test_1 import my_abs

print(my_abs(-1))

Empty functions
If you want to define an empty function that does nothing, you can use the pass statement:

def nop():
    pass

The pass statement does nothing, so what's the use? In fact, pass can be used as a placeholder. For example, if you haven't figured out how to write the code of the function, you can put a pass first so that the code can run.

pass can also be used in other statements, such as:

if age >= 18:
    pass

Without the pass, the code will run with syntax errors.
When calling a function, if the number of parameters is wrong, the Python interpreter will automatically check it out and throw a TypeError
, but if the parameter type is wrong, the Python interpreter will not be able to check it for us. Try the difference between my_abs and the built-in function abs:

>>> my_abs('A')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in my_abs
TypeError: unorderable types: str() >= int()
>>> abs('A')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'

When an inappropriate parameter is passed in, the built-in function abs will check the parameter error, and the my_abs we defined has no parameter check, which will cause an error in the if statement, and the error message is different from abs. Therefore, this function definition is not perfect.

Let's modify the definition of my_abs to check the parameter type and only allow integer and floating-point type parameters. Data type checking can be implemented with the built-in function isinstance():

def my_abs(x):
    if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
    if x >= 0:
        return x
    else:
        return -x

With parameter checking added, the function can throw an error if the wrong parameter type is passed in:

>>> my_abs('A')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in my_abs
TypeError: bad operand type

Returning Multiple Values ​​Can a
function return multiple values? The answer is yes.

import math

def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny

But in fact this is just an illusion, the Python function still returns a single value:

>>> r = move(100, 100, 60, math.pi / 6)
>>> print(r)
(151.96152422706632, 70.0)

Turns out the return value is a tuple! However, grammatically, the parentheses can be omitted when returning a tuple, and multiple variables can receive a tuple at the same time and assign the corresponding value by position. Therefore, the Python function returning multiple values ​​is actually returning a tuple, but it is more convenient to write. .

Summary
When defining a function, you need to determine the function name and the number of parameters;
if necessary, you can check the data types of the parameters first;
you can use return inside the function body to return the function result at any time;
when the function is executed and there is no return statement, it will automatically return None .
A function can return multiple values ​​at the same time, but is actually a tuple.

function arguments

When defining a function, we determine the names and positions of the parameters, and the interface definition of the function is completed. For the caller of the function, it is enough to know how to pass the correct parameters and what value the function will return. The complex logic inside the function is encapsulated, and the caller does not need to know.
Python's function definition is very simple, but it is very flexible. In addition to the required parameters that are normally defined, default parameters, variable parameters and keyword parameters can also be used, so that the interface defined by the function can not only handle complex parameters, but also simplify the caller's code.

default parameters
def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

Thus, when we call power(5), it is equivalent to calling power(5, 2):

>>> power(5)
25
>>> power(5, 2)
25

For other cases where n > 2, n must be passed in explicitly, such as power(5, 3).
As you can see from the above example, default parameters can simplify function calls. When setting the default parameters, there are a few points to pay attention to:
First, the mandatory parameters come first, and the default parameters come after, otherwise the Python interpreter will report an error (think about why the default parameters cannot be placed in front of the mandatory parameters);
Second, how to set Default parameters.
When there are multiple default parameters, the default parameters can be provided in order when calling, such as calling enroll('Bob', 'M', 7), which means that in addition to the two parameters of name and gender, the last one The parameter is applied to the parameter age. Since the city parameter is not provided, the default value is still used.

def enroll(name, gender, age=6, city='Beijing'):
    print('name:', name)
    print('gender:', gender)
    print('age:', age)
    print('city:', city)

It is also possible to provide some default parameters out of order. When some default parameters are provided out of order, the parameter names need to be written. For example, calling enroll('Adam', 'M', city='Tianjin') means that the city parameter uses the passed in value, and other default parameters continue to use the default value.
One thing to keep in mind when defining default parameters: default parameters must point to immutable objects!
The default parameters are very useful, but if used incorrectly, they will also fall into the pit. The default parameters have the largest pit, as shown below:

def add_end(L=[]):
    L.append('END')
    return L
>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']

First define a function, pass in a list, add an END and return:

>>> add_end()
['END']

However, when add_end() is called again, the result is wrong:

>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

The reason is explained as follows:
When the Python function is defined, the value of the default parameter L is calculated, that is [], because the default parameter L is also a variable, which points to the object [], each time the function is called, if the L is changed The content of the default parameter will be changed next time, and it is no longer the [] when the function is defined. (default parameters are actually present in memory)

Why design immutable objects such as str and None? Because once an immutable object is created, the data inside the object cannot be modified, which reduces errors caused by modifying data. In addition, since the object does not change, reading the object at the same time in a multitasking environment does not need to be locked, and there is no problem with reading at the same time. When we write a program, if we can design an immutable object, we should try to design it as an immutable object.

variable parameter

In Python functions, it is also possible to define variadic parameters. As the name implies, a variable parameter means that the number of parameters passed in is variable, which can be 1, 2 to any number, or 0.

Let's take a math problem as an example, given a set of numbers a, b, c..., please calculate a2 + b2 + c2 +... .

To define this function, we must determine the input parameters. Since the number of parameters is uncertain, we first thought that a, b, c... can be passed in as a list or tuple, so that the function can be defined as follows:

def calc(numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum
>>> calc([1, 2, 3])
14
>>> calc((1, 3, 5, 7))
84

If you use variadic parameters, the way to call the function can be simplified to this:

>>> calc(1, 2, 3)
14
>>> calc(1, 3, 5, 7)
84

So, let's change the function's parameter to a variadic parameter:

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

Defining a variable parameter is compared to defining a list or tuple parameter, only adding a * sign in front of the parameter. Inside the function, the parameter numbers receives a tuple, so the function code is completely unchanged. However, when calling this function, you can pass in any number of parameters, including 0 parameters:

>>> calc(1, 2)
5
>>> calc()
0

What if you already have a list or tuple and you want to call it with a variadic argument? This can be done like this:

>>> nums = [1, 2, 3]
>>> calc(nums[0], nums[1], nums[2])
14

*nums means to pass all the elements of the nums list as variable parameters. This notation is quite useful and common.

summarize
def product(x,*y):
    if len(y) == 0:
        if x is None:
            return TypeError
        else:
            return x
    else:
        sum = x
        for n in y:
            sum = sum * n
    return sum

# 测试
print('product(5) =', product(5))
print('product(5, 6) =', product(5, 6))
print('product(5, 6, 7) =', product(5, 6, 7))
print('product(5, 6, 7, 9) =', product(5, 6, 7, 9))
if product(5) != 5:
    print('测试失败!')
elif product(5, 6) != 30:
    print('测试失败!')
elif product(5, 6, 7) != 210:
    print('测试失败!')
elif product(5, 6, 7, 9) != 1890:
    print('测试失败!')
else:
    try:
        product()
        print('测试失败!')
    except TypeError:
        print('测试成功!')
product(5) = 5
product(5, 6) = 30
product(5, 6, 7) = 210
product(5, 6, 7, 9) = 1890
测试成功!
keyword arguments

Variable parameters allow you to pass in zero or any number of parameters, which are automatically assembled into a tuple when the function is called. The keyword arguments allow you to pass in 0 or any number of arguments with parameter names, and these keyword arguments are automatically assembled into a dict inside the function. See example:

def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

You can also pass in any number of keyword arguments:

>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, city=extra['city'], job=extra['job'])
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

*extra means to pass all the key-values ​​of the extra dict into the **kw parameter of the function with keyword parameters, kw will get a dict, note that the dict obtained by kw is a copy of extra, and the changes to kw will not be Affects extras outside the function.

Named Keyword Arguments
For keyword arguments, the caller of the function can pass in any unrestricted keyword arguments. As for what is passed in, you need to pass the kw check inside the function.
Still taking the person() function as an example, we want to check for city and job parameters:

def person(name, age, **kw):
    if 'city' in kw:
        # 有city参数
        pass
    if 'job' in kw:
        # 有job参数
        pass
    print('name:', name, 'age:', age, 'other:', kw)

But the caller can still pass in unrestricted keyword arguments:

>>> person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)
name: Jack age: 24 other: {'city': 'Beijing', 'addr': 'Chaoyang', 'zipcode': 123456}

If you want to limit the names of keyword arguments, you can use named keyword arguments, for example, only accept city and job as keyword arguments. The functions defined in this way are as follows:

def person(name, age, *, city, job):
    print(name, age, city, job)

Unlike keyword arguments *kw, named keyword arguments require a special separator , and arguments following * are treated as named keyword arguments.
The calling method is as follows:

>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer

If there is already a variadic parameter in the function definition, the following named keyword parameters no longer need a special delimiter *:

def person(name, age, *args, city, job):
    print(name, age, args, city, job)

Named keyword arguments must be passed in the parameter name, unlike positional arguments. If no parameter name is passed in, the call will report an error:

def person(name, age, *, city='Beijing', job):
    print(name, age, city, job)

Since the named keyword parameter city has a default value, it is not necessary to pass in the city parameter when calling:

>>> person('Jack', 24, job='Engineer')
Jack 24 Beijing Engineer

When using named keyword arguments, pay special attention, if there are no variadic arguments, you must add one as a special separator. If missing , the Python interpreter will not recognize positional and named keyword arguments:

def person(name, age, city, job):
    # 缺少 *,city和job被视为位置参数
    pass
parameter combination

To define a function in Python, you can use required parameters, default parameters, variable parameters, keyword parameters and named keyword parameters, all of which can be used in combination. Note, however, that the order of parameter definitions must be: required parameters, default parameters, variadic parameters, named keyword parameters, and keyword parameters.

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

When the function is called, the Python interpreter automatically passes in the corresponding parameters according to the parameter position and parameter name.

>>> f1(1, 2)                    #必选参数测试
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)                 #默认参数测试
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')        #可变参数测试
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)  #关键字参数测试
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)   #命名关键字参数测试
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}

The most amazing thing is that with a tuple and dict, you can also call the above function:

>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)         #我认为这样子写会让理解性变差
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)        
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)         
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}

So, for any function, it can be called by something like func(*args, **kw), no matter how its arguments are defined.
Although up to 5 parameters can be combined, do not use too many combinations at the same time, otherwise the intelligibility of the functional interface will be poor.

Guess you like

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