Functions that can accept any number of parameters
Defining a function in Python is very simple, such as a function that calculates a quadratic power:
def power(x): return x * x
If we want a function that can accept any number of parameters, how do we define it?
Let's say you want a function that accepts a set of data and calculates the sum of their squares.
Of course, you can pass directly the parameters of a list or tuple as a function:
def sum_power(x): sum = 0 for i in x: sum += i * i return sum
But to do so, if you want to use this function, you must first make a list or tuple, like this call:
sum_power([1,2,3,4])
It is much simpler to use the following method:
def sum_power(*x): sum = 0 for i in x: sum += i * i return sum
With the parameter at the beginning of * the position parameter after that will be treated as a sequence.
But what if you have a list arr = 1, 2, 3, 4, 5?
This function can be called as follows:
sum_power(*arr)
When a function is called, adding a * to a parameter such as a list is equivalent to splitting the list and passing in all elements as parameters of the function.
If you want to use any number of keyword parameters, you can use the parameters beginning with **.
>>> def a(**attrs): ... print(attrs) ... >>> a(name="Zhang San", age="18") {'name': 'Zhang San', 'age': '18'} >>>
It can be found that parameters starting with ** are packaged into dictionaries for processing.
def a(*args, **kwargs): pass
Functions like this can accept any number of positional and keyword parameters.
keyword-only parameter
When defining a function, the parameter at the beginning of * must be the last position parameter, while the parameter at the beginning of ** must be the last parameter. Think about why?
However, after the parameter at the beginning of *, it is acceptable to put a keyword parameter after the function at the beginning of * or a single *. This parameter will become a keyword-only parameter, which can only be used in the form of keywords.
For example:
def person(name, *, age): pass person("Zhang San", 12) #Error: TypeError: person() takes 1 positional argument but 2 were given person("Zhang San", age=12) #True
At this time, the first way to call the function will be wrong, must be in the form of the keyword age=12.
Using keyword-only parameters can improve code readability.
closure
Sometimes for classes that have only one method (except _init_(), we want to replace it with a function to simplify the code.
from urllib.request import urlopen class UrlTemplate: def __init__(self, template): self.template = template def open(self, **kwargs): return urlopen(self.template.format_map(kwargs)) # Use examples yahoo = UrlTemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}') for line in yahoo.open(names='IBM,AAPL,FB', fields='sllclv'): print(line.decode('utf-8'))
The UrlTemplate class here can be replaced by functions:
def urltemplate(template): def opener(**kwargs): return urlopen(template.format_map(kwargs)) return opener # Use examples yahoo = urltemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}') for line in yahoo(names='IBM,AAPL,FB', fields='sllclv'): print(line.decode('utf-8'))
Closure is a nested function, and external functions return internal functions as return values directly. Closure, as its name implies, is like a package that remembers the context in which it was defined. As in the example, the opener() function can remember the value of the urltemplate() parameter template and use it in subsequent calls.
Decorator
Sometimes we want to extend the function, but we don't want to modify the code of the function, so we can use the decorator. A decorator is essentially a function (or class) that accepts a function as input and returns a new function as output.
For example, we now need to add a log function to our function to print out the execution time of the function:
import time from functools import wraps def log(func): @wraps(func) def wrapper(*args, **kwargs): print("calling:{}".format(func.__name__)) start = time.time() result = func(*args, **kwargs) end = time.time() print(func.__name__, end-start) return result return wrapper # Use examples @log def f(x): while x < 1000000: x += 1
Call result:
>>> f(1) calling:f f 0.11393427848815918 >>>
If we don't use decorator, we need to write code in f() function. Not only does the original function become totally different, but if we want to add the recording function to other functions, we have to copy the code in the past. It's better to use decorator conveniently.
The part on which the ornament is used is essentially equivalent to:
def f(x): ... f = log(f)
The decorator function accepts the decorated function as a parameter and reassigns the variable of the original function name to the new function after returning.
Sweep code to pay attention to public numbers: