|
> 0))[ 0, 1, 4
,
9, 16 , 25, 36, 49, 64, 81]
In addition, functions can also be defined inside other function code blocks and can also be returned from other function calls.
|
def outer():
outer_var = "outer variable"
outer_var return inner
In the above example, we defined another function inner inside the function outer, and when the function outer is executed, the inner function will be returned. Furthermore, like any other Python object, functions can also be assigned to variables, as shown below:
|
def outer():
outer_var = "outer variable"
def inner ():
inner >>>
func =
outer
()>>> func< function inner at 0x031AA270 >
>>>
In the above example, when the outer function is called, it will return a function and assign the returned function to the variable func. Finally, the variable can be called just like the returned function:
|
>>> func ()
'outer variable' |
Function definition
The keyword def is used to create user-defined functions. Function definitions are some executable statements.
|
In the square function above, when the module containing the function is loaded into the Python interpreter, or if the function is defined in the Python REPL, the function definition statement def square(x) will be executed. However, this has some implications for default parameters with mutable data structures as values, which we will cover later. The execution of the function definition will bind the function name in the current local namespace (the namespace can be regarded as a mapping from name to value, and this mapping can also be nested. Namespaces and scopes will be detailed in another tutorial) Introduced) to a function object, which is a wrapper around the executable code in a function. This function object contains a reference to the current global namespace, which refers to the global namespace used when the function was called. In addition, the function definition does not execute the function body, which only executes when the function is called.
Function call parameters
In addition to normal parameters, Python functions also support a variable number of parameters. These parameters mainly fall into three categories described below:
1. Default parameter values: This allows the user to define some default values for the parameters of the function. In this case, the function can be called with fewer arguments. For arguments not provided when the function is called, Python will use the default provided values as these argument values. The following example demonstrates this usage:
|
def show_args(arg, def_arg=1, def_arg2=2):
return "arg={}, def_arg={}, def_arg2={}". format( arg, def_arg, def_arg2)
|
The definition of the above example function contains a normal position parameter arg and two default parameters def_arg and def_arg2. This function can be called in any of the following ways:
(1) Provide only non-default positional parameter values. In this example, the default parameters take the default values:
|
def show_ar gs(arg, def_arg =1, def_arg2=2):
"arg={}, def_arg={}, def_arg2={ }".format(arg, def_arg, def_arg2)
>>>
show_args("tranquility")
'arg=tranquility, def_arg=1, def_arg2=2'
(2) Override some default parameter values, including non-default positional parameters, with the provided values:
|
def show_args (arg, def_arg=1, def_arg2=2) :
arg={}, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2 )
>>>
show_args("tranquility", "to Houston") 'arg=tranquility, def_arg= to Houston, def_arg2=2'
(3) provides values for all parameters, which can be used to override the default parameter values:
|
def show_args( arg, def_arg=1, def_arg2=2):
return "arg={ }, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2 )
>> ") 'arg=tranquility, def_arg=to Houston, def_arg2=the eagle has landed'
Special care needs to be taken when using mutable default data structures as default parameters. Because the function definition is executed only once, these mutable data structures (reference values) are only created once when the function is defined. This means that the same mutable data structure will be used for all function calls, as shown in the following example:
|
def show_args_using_mutable_defaults(arg, def_arg=[]) :
("Hello World") return
"arg={}, def_arg={}"
.format( arg, def_arg) >>>
show_args_using_mutable_defaults
("test" ) "arg=test, def_arg=[' Hello World']"
>>>
show_args_using_mutable_defaults
("test 2") "arg=test 2, def_arg= ['Hello World', 'Hello World']"
In each function call, "Hello World" is added to the def_arg list, and after calling the function twice, there will be two "Hello World" strings in the default arguments. This is important to note when using variadic default parameters as default values. The reasons for this will become clear when we discuss the Python data model.
2. Keyword parameters: Using keyword parameters in the form of "kwarg=value" can also call functions. Among them, kwarg refers to the parameter name used in the function definition. Take the function defined below with default and non-default parameters as an example:
|
def show_args( arg, def_arg=1 ):
return "arg={}, def_arg={}". , def_arg)
To demonstrate calling a function using keyword arguments, the following function can be called in either of the following ways:
|
show_ar gs(arg="test", def_arg=3)
|
In a function call, keyword arguments must not come before non-keyword arguments, so the following calls will fail:
A function cannot provide duplicate values for a parameter, so the following calling method is illegal:
|
show_ar gs("test", arg ="testing")
|
In the above example, the parameter arg is a positional parameter, so the value "test" will be assigned to it. Trying to assign it again to the keyword arg means you are attempting a multiple assignment, which is illegal.
All keyword parameters passed must match the parameters accepted by a function, and the order of keywords including non-optional parameters is not important, so the following writing with the parameter order reversed is legal:
|
show_args (def_arg="testing", arg="test")
|
3. Arbitrary parameter list: Python also supports defining such a function, which can accept any number of parameters passed in the form of tuples. An example in the Python tutorial is as follows:
|
def write_multiple_items(file, separator, * args):
file .write(separator.join(args))
|
Any number of parameters must follow the normal parameters. In this example, any number of parameters exist after the parameters file and separator. Here is an example of calling the function defined above:
|
f = open("test .txt", "wb" )
write_multiple_items(f, " ", "one", "two", " three", "four", "five")
|
The above parameters one, two, three, four, and five are bundled together to form a tuple, which can be accessed through the parameter args.
Unpack function parameters
Sometimes, the parameters of a function call may exist in the form of tuples, lists, or dictionaries. These parameters can be unpacked inside the function for invocation by using the "*" or "**" operators. Take the following function as an example. This function accepts two positional parameters and prints out the values of the two parameters.
|
def print_args(a, b) :
print a
print b
|
If the parameter values provided to the function are in list form, then we can unpack these values directly into the function as follows:
|
> > >>> print_args (*args)12
Similarly, when we have keywords, we can use a dictionary to store the mapping relationship from kwarg to value, and use the "**" operator to unpack the keyword parameters to the function, as shown below:
|
>>> def par rot(voltage, state='a stiff', action='voom'):
" -- This parrot wouldn't"
, action, voltage,
"volts through it." "!"
>> , "state" : "bleedin' demised", "action": "VOOM"}>> > parrot (**d)>>>
This parrot wouldn't VOOM if you put four million volts through it. E's bleed in' demised Use "*" and "**" to define functionsSometimes, when defining a function, we may not know the number of parameters before. This results in the following signed function definition:
|
arg
,
*
args |
*
The "*args" parameter represents the unknown positional parameter sequence length, while "**kwargs" represents a dictionary containing keyword and value mapping relationships. It can contain any number of keywords and value mappings, and is specified in the function definition "*args" must be in front of "**kwargs". The code below demonstrates this situation:
1
2
3
4
5
6
7
8
9
10
11 12
13
14
15 16
17
18
|
def show_args(arg, * args, ** kwargs):
print arg
in args:
args
for
key
, value in kwar gs: , value
>>> args = [1, 2, 3, 4]
>>> kwargs = dict(name='testing', age=24, year=2014)
>>> show_args("hey", *args, **kwargs)
hey
1
2
3
4
age 24
name testing
year 2014
|
Normal parameters must be provided to the function, but "*args" and "**kwargs" are optional, as shown below:
,
* args
,* |
kwargs
In function calls, ordinary parameters are provided in the normal way, while optional parameters can reach the function call in unpacked form.
Anonymous Functions
Python also supports anonymous functions, which are created using the lambda keyword. The form of a Lambda expression in Python is as follows:
|
lambda_expr ::= "lambda" [parameter_list]: expression
|
Lambda expression returns the evaluated function object and has the same properties as the named function. In Python, Lambda expressions are usually only used for very simple functions, like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
>>> square = lambda x: x **2
>>> for i in range (10):
square(i)
0
1
4
9
16
25
36
49
64
81
>>>
|
The lambda expression above does the same thing as the named function below:
|
def square (x):
return x**2
|
Nested functions and closures
Defining a function inside a function creates a nested function, as shown below:
|
```python
def outer():
outer_var = " outer variable"
outer_var ```
In this type of function definition, the function inner is only valid inside the function outer, so when the inner function needs to be returned (moved to the outer scope) or passed to another function, using nested functions is usually More convenient. In the nested function above, a new nested function instance is created every time the outer function is called. This is because the inner function definition is executed every time the outer function is executed, and its function body is will not be executed.
A nested function has access to the environment in which it was created, which is a direct result of Python's function definition semantics. One consequence is that variables defined in the outer function can be referenced in the inner function, even after the outer function has completed execution.
|
def outer():
outer_var = "outer variable"
def inner ():
outer_var
return
inner
>>>
x = outer() >>>
x
> Internally nested functions refer to variables in external functions When , we say that the nested function is closed relative to the reference variable. We can access this enclosed variable using a special attribute "__closure__" of the function object as shown below:
|
>>>
cl
|
>>>
cl (<cell at 0x029E4470: str object at 0x02A0FD90 >,) >>> cl[0].cell_contents
'outer variable'
Closures in Python have a weird behavior. In Python 2.x and lower, variables pointing to immutable types (such as strings and numbers) cannot be bounced within closures. The following examples illustrate this:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def counter():
count = 0
def c() :
count return c
>> c(
) Traceback (
most
recent call last ) :
File "", line 1, in <module>
File "", line 4, in c
UnboundLocalError: local variable 'count' referenced before assignment
|
A rather unreliable solution is to use a mutable type to capture the closure, like this:
1
2
3
4
5
6
7
8
9 :
count = | [
0]def
count
[0] += 1
return c >> > c
= counter()>>> c
|
Python 3 introduced the "nonlocal" keyword to solve the closure scope problem shown below. In the namespaces section of this tutorial, we describe these quirks in more detail.
1
2
| def
counter():
count
= 0
nonlocal
count 1
Closures can be used to maintain state (different from classes). In some simple cases, they can also provide a solution that is more concise and readable than classes. We use tech_pro A logging example to illustrate this point. Assume a very simple logging API that uses class-based object-oriented ideas and can print logs at different levels:
1
2
3
4 5
6
7
8
9
10. self | ,
level):
self._level = level def
__call__
(self, message ):
_level
, message)) log_info =
Log
("info")
log_warning = Log("warning")
log_error = Log("error")
|
The same functionality can also be achieved using closures as follows:
|
def make_log(level):
def _(message) :
{}: {}".format(level, message)) return
_ log_info
=
make_log("info")log_warning
=
make_log("warning") log_error
=
make_log("error")
|
It can be seen that even though both versions implement the same functionality, But the closure-based version is cleaner and more readable. Closures also play a very important role in one of the main Python functions called "Function Modifiers", which are very widely used features and we will explain them in the next tutorial.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|