[Python learning] Python function

No parameter, no return function

def test1():
    print("I am a parameterless function with no return value")


test1()

Function with parameters and no return value: if you need to dynamically adjust a processing information in the function body, you can receive relevant data in the form of parameters

def test2(num):
    print(num ** 1)
    print(num ** 2)
    print(num ** 3)


test2(3)

Function with parameters and return values: if you need to dynamically adjust a processing information in the function body, you can receive relevant data in the form of parameters, and a value will be returned after the function is executed

def test3(num):
    a = num +1
    return a


result = test3(4)
print(result)

Function with parameters: when multiple processing information in the function body needs to be dynamically adjusted, it can be separated by commas to receive multiple parameters

def test4(num1, num2):
    print(num1 + num2)


test4(3,4)  # Input the arguments directly, and the formal parameters correspond to the arguments one by one


test4(num2=5, num1=4) # Parameters are passed by keyword, not by parameter order

For functions with indefinite length parameters, you need to add an "*" before the formal parameter, that is, tuples as parameters

def test5(*t):
    print(t, type(t))
    result = 0
    for i in t:
        print(i)
        result += i
    print(result)


test5(1,2,3,4,5)

For functions with indefinite length parameters, you need to add a "* *" before the formal parameter, that is, it is similar to the dictionary as the parameter. When calling the function, you must enter the parameter in the form of keyword

def test6(**kwargs):
    print(kwargs, type(kwargs))


test6(name="larry", age=18, sex="male")

Unpacking and packaging of parameters

Packaging: package the parameters passed into a set, which is called "packaging"

def mySum(a,b,c,d):
    print(a + b + c + d)

def test7(*args):
    # Packaging, * args represents unpacking, representing data one by one, args represents packaging, representing a whole
    print(args)
    # For unpacking, a * should be used for unpacking operation, not * for packaging operation
    print(*args)
    print(args[0],args[1], args[2], args[3])
    mySum(*args)

test7(1,2,3,4)

Unpacking: decomposing the set parameters into separate individuals again, which is called "unpacking"

def mySum(a,b,c):
    print(a)
    print(b)
    print(c)

def test8(**kwargs):
    # Packing, * * kwargs represents unpacking, representing data one by one, kwargs represents packing, representing a whole
    print(kwargs)
    # For unpacking, two * * should be used for unpacking operation, not * for packaging operation
    # print(**kwargs)  # You can't print this * * kwargs directly. You need to receive the corresponding functions and parameters
    mySum(**kwargs)

test8(a="sz", b=18, c="male")   # When calling, you must also enter the corresponding keyword, otherwise an error will be reported and the corresponding keyword cannot be found
# Function return value
def test9(a,b):
    he = a + b
    cha = a - b
    return (he, cha)

# res is a collection
res = test9(4, 5)
# Unpacking:
he, cha = test9(4, 5)
print(res)
# Unpacking of res set
print(res[0], res[1])
print(he, cha)

=======================Description of function=

# For the description of general functions, the following information needs to be explained: function, meaning and type of parameters, whether they can be omitted, default value, meaning and type of return value
def mySum(a, b=1):
    """
    Calculate the sum and difference of two words
    :param a: Value 1, value type, not optional, no default value
    :param b: Value 2, value type, optional, default value: 1
    :return: Returns the result of calculation, tuple type: (sum, difference)
    """
    he = a + b
    cha = a - b
    return (he, cha)

help(mySum)

#------------------------Advanced usage of functions------------------------

Partial function: when we write a function with many parameters, if some parameters have a fixed value in most scenarios, in order to simplify the use, we can create a new function and specify a parameter of the function we want to use as a fixed value. This new function is "partial function"

import functools
def test10(a,b,c,d=1):
    res = a + b + c + d
    print(res)

# test10(1,2,3)
#
# # Then define a partial function
# def test11(a,b,c,d=2):
#     test10(a,b,c,d)
#
# test11(1,2,3)

# Use a function of python to create a partial function through the partial class of functools module without specifying the value of the parameter
newFunc = functools.partial(test10, c=5, d=2)
newFunc(1,2)  # This is the new partial function. Just enter two parameters, and the other parameters use the default fixed values

# Usage scenarios of partial functions, such as the int() function. The int() function has a parameter of base, which is used to specify which "base" to convert to an int integer and convert the numeric string to a base
numStr = "10010"

# Import the functools module, use the partial method inside, specify base=xx, and then generate a partial function
import functools
intTransfer = functools.partial(int, base=16)
res = intTransfer(numStr)
print(res)

======================Higher order function=

High order function. If the parameters of a function can receive a function, this function is called a high-order function

l = [{"name":"sz", "age":18}, {"name":"sz2", "age":19}, {"name":"sz3", "age":18.5}]
# Define a function to sort the selected fields in the l list. This function will receive each element in the l list
def getKey(x):
    return x["name"]

result = sorted(l, key=getKey, reverse=-1)
print(result)

Examples of higher order functions

def caculate(num1, num2, caculateFunc):
    result = caculateFunc(num1, num2)
    print(result)

def sum(a, b):
    return a + b

def jianfa(a, b):
    return a - b

caculate(num1=6, num2=2, caculateFunc=jianfa)

======================Return function=

Return function: refers to a function that returns data from another function. This operation is called "return function"

Case: obtain different operations and make different calculations according to different parameters

def getFunc(flag):
    # 1. Define several functions again
    def sum(a, b, c):
        return a + b + c

    def jian(a, b, c):
        return a - b - c

    # 2. Return different operation functions according to different flag values
    if flag == "+":
        return sum   # Instead of calling the sum function, the sum function is returned because there is no addition ()
    elif flag == "-":
        return jian  # The function jian is returned instead of calling the function jian, because there is no addition ()

backFunc = getFunc("-")  # The parameter passed in flag is "+", the returned function is sum, the flag is "-", and the returned function is jian
print(backFunc, type(backFunc))
res = backFunc(1,2,3)  # backFunc is a return function, so you can call this function and pass in parameters
print(res)

======================Anonymous function=

Anonymous functions, also known as "lambda functions", as the name suggests, are functions without names

newFunc2 = lambda x, y : x + y
res = newFunc2(1,2)
print(res)


l = [{"name":"sz", "age":18}, {"name":"sz2", "age":19}, {"name":"sz3", "age":18.5}]

# Define a function to sort the selected fields in the l list. This function will receive each element in the l list
# def getKey(x):
#     return x["name"]

result = sorted(l, key=lambda x : x["age"])
print(result)

======================Closure=

On the premise of function nesting, the inner function references the variables or parameters of the outer function, and the outer function returns the inner function as a return value

Then, the outer variable referenced by the inner function + is called "closure"

def test11():
    a = 10
    def test12():
        print(a)

    return test12

newFunc3 = test11()
newFunc3()

Application scenario: the outer function generates functions with different functions according to different parameters

Case: generate different split line functions according to the configuration information

def line_config(content, length):
    def line():
        print(("-" * (length // 2)) + content + ("-" * (length // 2)))

    return line

newFunc4 = line_config("aaaa", 20)
newFunc4()

newFunc5 = line_config("bbbb", 10)
newFunc5()

To modify the variables of the outer function through closures, you must use the nonlocal keyword

def test13():
    num = 1
    def test14():
        nonlocal num
        num = 6
        print(num)

    print(num)
    test14()
    print(num)

    return test14

newFunc5 = test13()
newFunc5()

Closure note 2:

def test15():
    a = 1
    def test16():
        print(a)

    a = 2
    return test16

newFunc6 = test15()
newFunc6()

Closures, more complex examples

def test17():

funcs = []

for i in range(1,4):

def test18():

print(i)

funcs.append(test18)

return funcs

newFuncs = test17()

print(newFuncs)

newFuncs0

newFuncs1

newFuncs2

def test17():
    funcs = []
    for i in range(1,4):
        def test18(num):
            def inner():
                print(num)
            return inner
        funcs.append(test18(i))  # This represents the addition of the returned inner function and the value of the corresponding i
    return funcs

newFuncs = test17()
print(newFuncs)
newFuncs[0]()
newFuncs[1]()
newFuncs[2]()

=========================Function decorator=

Function: add some extra code to a function without changing the function name and function body

Case: send words and pictures

1. Define two functions

1. Define two functions

def checkLogin(func):   # Decorator function. In order to add some additional small functions to fss() and ftp() functions, you can define a decorator function
    def inner():
        print("validate logon...")  # Add additional function code
        func()   # Incoming function
    return inner  # Returns an internal function that adds additional function code to the incoming function

#The syntax pattern of python is actually a design pattern, which is similar to calling the checkLog (func) function and reflecting an internal function,
# And the returned function name is the same as the kicker's function name
@checkLogin   # @checkLogin syntax sugar, return a function with the same name as the following function, and add other function codes to this function
def fss():
    print("Say it")
# fss = checkLogin(fss)

#The syntax pattern of python is actually a design pattern, which is similar to calling the checkLog (func) function and reflecting an internal function,
# And the returned function name is the same as the kicker's function name
@checkLogin   # @checkLogin syntax sugar, return a function with the same name as the following function, and add other function codes to this function
def ftp():
    print("Send pictures")
# ftp = checkLogin(ftp)


# 2. Relevant logic codes
btnIndex = 1
if btnIndex == 1:
    fss()
else:
    ftp()

Summary: it is necessary to separate the function part from the business logic code part

There must be a premise for sending pictures, that is, the user must log in

Actions for login authentication

1. Modify directly in the business logic code and add a verification operation: the disadvantages are as follows:

Because there are so many business logic codes, it is necessary to perform login verification for each logic code before calling specific function functions,

Code redundancy is relatively large, and the reusability of the code is relatively poor, and the maintainability of the code is relatively poor

2. Modify directly in the function function to facilitate code reuse: this also has a problem. The login verification code is repeated

Improvement method: define a login verification function checkLogin (), and then call the function of checkLogin () in the function of sending words and pictures

==============Decorator with parameters, and decorator with indefinite length=

def zsq(func):
    def inner(*args, **kwargs):
        print("_" * 30)
        res = func(*args, **kwargs)
        return res
    return inner

@zsq
def pnum1(num1, num2, num3):
    print(num1, num2, num3)
    return num1 + num2 + num3    # Add the return value of the function function, and the decorator should also be written in the form of constant

@zsq
def pnum2(num):
    print(num)
    return num

@zsq
def pnum3(*args, **kwargs):
    print(*args, **kwargs)

res1 = pnum1(1,2, num3=666)   # To execute the pnum1() function here is to execute the inner function
res2 = pnum2(999)             # Executing the pnum2() function here is to execute the inner function
res3 = pnum3(1,2,3,4,5,56,6)  # To execute the pnum3() function here is to execute the inner function
print(res1,res2,res3)         # Print view return value

==============Return the function of the decorator and control the parameter value in the decorator through parameters=

def getZsq(char):                           # Returns the decorator function in a fixed format. It controls the parameter value in the decorator's internal function through parameters
    def zsq(func):                          # Decorator function is also a fixed format
        def inner(*args, **kwargs):         # The function returned by the closure is also in a fixed format
            print(char * 30)
            res = func(*args, **kwargs)     # The function function has a fixed writing method of return value and a fixed format
            return res                      # Returns the value of the function
        return inner                        # Returns the internal function to add new functions. It is also a fixed format
    return zsq                              # Return the decorator inside, which is also a fixed format


@getZsq("*_")        # Call the function that returns the decorator and pass in the parameter value required to control the internal function of the decorator
def f1(num):
    print("666", num)
    return num

res1 = f1(2)
res2 = f1(3)
print(res1, res2)

=========================python generator=

Iterator: it is a special iterator (the abstract level of iterator is higher). Therefore, it has the characteristics of iterator: lazy computing data and saving memory; Able to record status,

And access the next state through the next () function, which has the characteristics of iteration

Iterator is just a way to produce data. If you need any data, you can directly call a function to generate a data

1. How to create a generator: generator expression, modify [] of list derivation formula to ()

l1 = [i for i in range(1,10) if i % 2 == 0]    # This is the derivation of list [], which will load all data into memory
l2 = (i for i in range(1,20) if i % 2 == 0)    # When the list [] is changed to (), it becomes a generator expression, and the result of this expression is a generator object
print(l1)
print(l2)
print(l2.__next__())
print(l2.__next__())  # The iterator will record the current state location, know where to go next and what data to take, and will not load all the data into memory at once
print(next(l2))       # next(l2) and L2__ next__ () is the same function to obtain the next data
for i in l2:
    print("for Iteration:",i)

2. Generate a generator through the generator function. The function contains a yield statement. The execution result of this function is "generator"

For the yield statement, you can block the execution of the current function. Then, when you use the next() function or next(), the function will continue to execute. Then, when you execute the next yield statement

Wait, it will be suspended again

def test():
    yield 1
    print("a")

    yield 2
    print("b")

    yield 3
    print("c")

    yield 4
    print("d")

g = test()
print(g)
print(g.__next__())
print(g.__next__())
print(g.__next__())

Another way to write a producer is the for loop

def test():
    for i in range(1,10):
        yield i

g = test()
print(g)
print(g.__next__())
print(next(g))
print(g.__next__())
print(next(g))

=================Generator's send() method=

send() method. The send() method has a parameter that specifies the return value of the last suspended yield statement. Compared with the. next() method, you can pass additional values to the yield statement

Notice the first call to t.send(None)

def test():
    res1 = yield 1
    print(res1)

    res2 = yield 2
    print(res2)

    res3 = yield 3
    print(res3)

g = test()
print(g.send(None))   # When the send() method is used for the first time, the parameter must be None,
print(g.__next__())
print(g.send("000"))

==============Generator shutdown=

# Method to close the generator, g.close()
# First write a generator function
def test():
    yield 1
    print("a")

    yield 2
    print("b")

    yield 3
    print("c")

# Through the generator function, Mr. becomes a generator g
g = test()

# You can operate on the generator g below
print(g.__next__())
print(g.__next__())
g.close()   # The close () method of the producer means that the state of the generator is guided to the end of the generator, and an error StopIteration will be reported when calling again
print(g.__next__())

================Generator considerations=

Generator, what happens if you encounter a return statement? How many times can you traverse it

1. During the execution of the generator, once a return statement is encountered, it will immediately stop, report an error StopIteration, and enter the value after return

def test1():
    yield 1
    print("aa")

    # return 10

    yield 2
    print("bb")

    yield 3
    print("cc")

# Through the generator function, Mr. becomes a generator g
g = test1()

# You can operate on the generator g below
print(g.__next__())
print(g.__next__())  # When this code is executed, the return statement will be executed, and an error StopIteration will be reported and the value after return will be returned
print(g.__next__())

2. The generator value can be traversed once. If you want to traverse again, you need to get the generator again

def test2():
    yield 1
    print("aaa")

    # return 10

    yield 2
    print("bbb")

    yield 3
    print("ccc")

# Through the generator function, Mr. becomes a generator g
g = test2()

for i in g:    # When for traverses the generator, the code below the last yield statement in the generator can be executed
    print(i)

print("Current execution location xxxxxxxx´╝îThe following code will not be executed")
for i in g:    # When traversing the generator for the second time, it will not be executed. The previous print () function represents the execution position, which needs to be used	
	print(i)   # Get the generator again
	

========Recursive function=



! [insert picture description here]( https://img-blog.csdnimg.cn/c447b4570a194120ab93dd8e04a85b28.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAZ2FvZ3Nm,size_20,color_FFFFFF,t_70,g_se,x_16

====================Recursive function=

Recursive function: inside function A, continue to call function A

Recursive function: first there is transfer, that is, query; then there is regression, and the value is transferred

# Case: find the factorial of a number, such as the factorial of 9: 9! = 9 * 8 * 7 * 6 * 5 *... * 2 * 1
# Function: decompose the data without directly knowing the result,
def jieCheng(n):
    if n == 1:      # Here is the position condition of the end of the transfer and the beginning of the regression
        return 1
    # The following must be the case of n! = 1
    return n * jieCheng(n-1)

result = jieCheng(3)
print(result)

======================Scope of function=

python does not have a block level scope, such as if and while. Other languages have a block level scope (it cannot be accessed outside the block)

a = 10                  # a is G, the global variable, and the scope is within the whole document
def test3():
    b = 9               # b is E, the namespace of the external nested function
    print(b)
    def test4():
        c = 8           # c is L, local variable
        print(b)
        return c
    return test4
print(__name__)         # __name _ is B, python built-in variable, which can be used in each file
print(a)
newFunc = test3()
res = newFunc()
print(res)


Tags: Python Back-end

Posted on Fri, 03 Dec 2021 00:08:15 -0500 by transformationstarts