Python basic tutorial: custom function

Polymorphism

We can see that Python does not need to consider the input data type, but hands it to specific code to judge and execute. The same function (such as the addition function here my_sum()) can be applied to integers, lists, and characters at the same time String and so on.

In programming languages, we call this behavior polymorphism. This is also a big difference between Python and other languages, such as Java and C. Of course, this convenient feature of Python will also bring many problems in actual use. Therefore, if necessary, please add data type checking at the beginning.

def my_sum(a, b):
    if type(a) == type(b):
        if isinstance(a, (int, str, list)):
            return a + b
        else:
            raise Exception("input is not int/str/list")
    else:
        raise Exception("input type is not same")

print(my_sum(3, 5))
# 输出
# 8

print(my_sum([1, 2], [3, 4]))
# 输出
# [1, 2, 3, 4]

print(my_sum('hello ', 'world'))
# 输出
# hello world

print(my_sum([1, 2], 'hello'))
# 输出
# input type is not same

Function nesting

Another major feature of Python functions is that Python supports nesting of functions. The so-called function nesting means that there are functions inside the function, such as:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def f1():
    print('hello')
    def f2():
        print('world')
    f2()
f1()

# 输出
hello
world

Benefits of nesting

1. The nesting of functions can ensure the privacy of internal functions.

Internal functions can only be called and accessed by external functions, and will not be exposed to the global scope. Therefore, if you have some private data (such as database user, password, etc.) inside your function that you don’t want to be exposed, then you can use The nesting of the function encapsulates it in the inner function and can only be accessed through the outer function. such as:

def connect_DB():
    def get_DB_configuration():
        ...
        return host, username, password
    conn = connector.connect(get_DB_configuration())
    return conn

Here's function get_DB_configurationis an internal function, it can not connect_DB()be called other than a separate function. In other words, the following external direct calls are wrong:

get_DB_configuration()

# 输出
NameError: name 'get_DB_configuration' is not defined

2. Reasonable use of function nesting can improve the operating efficiency of the program.

Look at the following example:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def factorial(input):
    # validation check
    if not isinstance(input, int):
        raise Exception('input must be an integer.')
    if input < 0:
        raise Exception('input must be greater or equal to 0' )

    def inner_factorial(input):
        if input <= 1:
            return 1
        return input * inner_factorial(input-1)
    return inner_factorial(input)

print(factorial(5))

Here, we use a recursive method to calculate the factorial of a number. Because it is necessary to check whether the input is legal before calculation, it is written in the form of function nesting, so that whether the input is legal is only checked once. And if we don't use function nesting, it will be checked every time the recursion is called. This is unnecessary and will reduce the efficiency of the program.

In actual work, if you encounter a similar situation, the input check is not fast, and it will consume a certain amount of resources, so it is necessary to use function nesting.

Function variable scope

1. Local variables have higher priority than global variables

If you encounter a situation where a local variable and a global variable inside a function have the same name, then inside the function, the local variable will cover the global variable, such as the following:

MIN_VALUE = 1
MAX_VALUE = 10
def validation_check(value):
    MIN_VALUE = 3
    ...

HereMIN_VALUE=3

2. You cannot change the value of global variables at will within the function

VALUE = 1
MAX_VALUE = 10
def validation_check(value):
    ...
    MIN_VALUE += 1
    ...
validation_check(5)

If you run this code, the program will report an error:

UnboundLocalError: local variable 'MIN_VALUE' referenced before assignment

This is because the Python interpreter defaults the variables inside the function as local variables, but it also finds that the local variable MIN_VALUE is not declared, so it cannot perform related operations. Therefore, if we must change the value of global variables inside the function, we must add the declaration global:

MIN_VALUE = 1
MAX_VALUE = 10
def validation_check(value):
    global MIN_VALUE
    ...
    MIN_VALUE += 1
    ...
validation_check(5)

The global keyword here does not mean that a global variable is recreated MIN_VALUE, but it tells the Python interpreter that the variable inside the function MIN_VALUEis the previously defined global variable, not a new global variable, nor a local variable. In this way, the program can access the global variable inside the function and modify its value.

3. For nested functions, the inner function can access the variables defined by the outer function, but it cannot be modified. If you want to modify it, you must add the keyword nonlocal:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def outer():
    x = "local"
    def inner():
        nonlocal x # nonlocal关键字表示这里的x就是外部函数outer定义的变量x
        x = 'nonlocal'
        print("inner:", x)
    inner()
    print("outer:", x)
outer()
# 输出
inner: nonlocal
outer: nonlocal

Closure

Closure is similar to the nested function just mentioned, the difference is:

  • In the nested function, the outer function returns a specific value
  • The external function in the closure returns a function, and the returned function is usually assigned to a variable, which can be executed later.

For example, if we want to calculate the n-th power of a number, we can write the following code with a closure

def nth_power(exponent):
    def exponent_of(base):
        return base ** exponent
    return exponent_of # 返回值是exponent_of函数

square = nth_power(2) # 计算一个数的平方
cube = nth_power(3) # 计算一个数的立方 
square
# 输出
<function __main__.nth_power.<locals>.exponent(base)>

cube
# 输出
<function __main__.nth_power.<locals>.exponent(base)>

print(square(2))  # 计算2的平方
print(cube(2)) # 计算2的立方
# 输出
4 # 2^2
8 # 2^3

Note that, in the implementation of complete square = nth_power(2)and cube = nth_power(3)after the external function nth_power()parameter exponent, the internal function will still be exponent_of()remembered. In this way, when we call square(2) or cube(2) later, the program can output the result smoothly without reporting an error that the parameter exponent is not defined.

Closures solve the basic variable problem of function operation, especially when this function needs to be called multiple times.

Supplement: UnboundLocalError

Although the function will not be executed without being called, the python interpreter will do some variable detection or type detection, such as whether there is a yield, if there is, then it will be marked as a generator, which is compiled into bytes The code is already determined.

import dis
x = 1
y = 2


def foo():
    print(x)
    x = 2
    print(y)

dis.dis(foo)

# 直接调用 foo() 会报错
# UnboundLocalError: local variable 'x' referenced before assignment

# 输出
  7           0 LOAD_GLOBAL              0 (print)
              2 LOAD_FAST                0 (x)
              4 CALL_FUNCTION            1
              6 POP_TOP

  8           8 LOAD_CONST               1 (2)
             10 STORE_FAST               0 (x)

  9          12 LOAD_GLOBAL              0 (print)
             14 LOAD_GLOBAL              1 (y)
             16 CALL_FUNCTION            1
             18 POP_TOP
             20 LOAD_CONST               0 (None)

Guess you like

Origin blog.csdn.net/qdPython/article/details/112787489