语言基础篇11——函数、函数参数类型、装饰器、生成器

函数

基本结构

def func_name(value):
    print(f"Hello {value}")
    return 0

func_name("World")

函数参数

参数默认值和五种参数类型

https://docs.python.org/3/glossary.html#term-parameter

参数默认值

带默认值的参数必须在参数列表右边

def func_name(a, b=0):
    return a + b

print(func_name(1))

位置或关键字参数,positional-or-keyword argument

默认参数类型,传参的时候可以以位置或者关键字形式传递,但位置参数一定在左,关键字参数一定在右

# a、b均为位置或关键字参数,a以位置参数的形式传递,b以关键字参数的形式传递
def func_name(a, b):
    return a + b

print(func_name(1, b=2))

仅位置参数,positional-only argument

使用/用于限定其之前的参数为仅位置参数类型

# a、b均为位置参数,c为位置或关键字参数但以位置参数形式传入
def func_name(a, b, /, c):
    return a + b + c

print(func_name(1, 2, 3))

仅关键字参数,keyword-only argument

使用*用于限定其之后的参数为仅关键字参数类型

# a、b为位置或关键字参数但以位置参数传入,c为仅关键字参数
def func_name(a, b, *, c):
    return a + b + c

print(func_name(1, 2, c=3))

可变位置参数,var-positional argument

a、b为仅位置参数,args为可变位置参数,*args将多余的位置参数装包为元组args,args命名任意,习惯上以args作为可变位置参数名

def func_name(a, b, *args):
    print(a, b, args, type(args))  # 1 2 (3, 4, 5) 

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

可变关键字参数,var-keyword argument

a、b均为位置或关键字参数,但a、b传入形式不同,**kwargs将多余的关键字参数装包为字典kwargs,kwargs命名任意,习惯上以kwargs作为可变关键字参数名

def func_name(a, b, **kwargs):
    print(a, b, kwargs, type(kwargs))  # 1 2 {'c': 3, 'd': 4, 'f': 5} 

func_name(1, b=2, c=3, d=4, f=5)

注:

  1. 整体上,参数传入时必然以位置参数或关键字参数的形式传入,通常联合使用*args**kwargs接受任意参数

    def func_name(*args, **kwargs):
        print(args, kwargs)
    
    func_name(1, b=2, c=3, d=4, f=5)
    
  2. a、b为位置参数,c、d为位置或关键字参数,e、f为关键字参数

    def func_name(a, b, /, c, d, *, e, f):
        print(a, b, c, d, e, f)
    
    func_name(1, 2, 3, d=4, e=5, f=6)
    

函数返回值

Python基于元组的自动装包和拆包在语法上实现了多个返回值形式,实际仍为一个返回值

def func_name(a, b):
    return a, b


a, b = func_name(1, 1)
print(a, b)  # 1 1

r = func_name(1, 1)
print(r, type(r))  # (1, 1) 

Python函数返回值默认为None,不存在没有返回值的情况

def func_name1():
    return
print(func_name1())  # None


def func_name2():
    pass
print(func_name2())  # None

匿名函数,lambda表达式

def pow2(n):
    return n ** 2
print(pow2(10))

calc = lambda n: n ** 2
print(calc(10))

add = lambda x, y: x + y

l = [-2, 4, -9, 4, 7, 8]
print(max(l, key=lambda n: n * n))

闭包函数

  • 闭包函数必须有内嵌函数
  • 内嵌函数需要引用该嵌套函数上一级中的变量
  • 闭包函数必须返回内嵌函数
# 闭包函数通过将函数名作为返回值使得不释放局部变量引用而保留局部变量
# 具有环境变量n的函数power
def nth_power(a):
    n = a or 1

    def power(base):
        return base ** n

    return power


_3power = nth_power(3)
print(_3power(2))  # 8

_closure_

def generate_func(start, end):
    def print_string(name):
        print(start, name, end)

    return print_string


hello = generate_func("Hello", "!")
hello('World')  # Hello World !
print(hello.__name__)  # print_string
print(
    hello.__closure__)  # (, )
print(hello.__closure__[0].cell_contents)  # !
print(hello.__closure__[1].cell_contents)  # Hello
print(id(hello))  # 2292892980448

bye = generate_func("Bye", ".")
bye('World')  # Bye World .
print(bye.__name__)  # print_string
print(
    bye.__closure__)  # (, )
print(bye.__closure__[0].cell_contents)  # .
print(bye.__closure__[1].cell_contents)  # Bye
print(id(bye))  # 2292892978368

global

a = 1


def f1():
    a = 2

    def f2():
        global a
        a = 3
        print(a)  # 全局变量a=3

    f2()
    print(a)  # 局部变量a=2


f1()
print(a)  # 全局变量a=3

nonlocal

a = 1


def f1():
    a = 2

    def f2():
        nonlocal a
        a = 3
        print(a)  # 全局变量a=3

    f2()
    print(a)  # 局部变量a=3


f1()
print(a)  # 全局变量a=1

装饰器

import time


def outer(func):
    def inner(*args, **kwargs):
        t1 = time.perf_counter()
        res = func(*args, **kwargs)
        print(time.perf_counter() - t1)
        return res

    return inner


def add(a, b):
    time.sleep(1)
    return a + b


add_plus = outer(add)
print(add_plus(1, 2))
# 1.0007887999818195
# 3


@outer
def sub(a, b):
    time.sleep(1)
    return a - b


print(sub(1, 2))
# 1.000871800002642
# -1
# 装饰器标准模板
# 装饰器函数\装饰器类,以函数作为装饰器\以类作为装饰器
def wrapper():
    def outer(func):
        def inner(*args, **kwargs):
            res = func(*args, **kwargs)
            return res

        return inner

    return outer


@wrapper()
def func_wrapped():
    pass


func_wrapped()

无参装饰器

# 无参装饰器
def debug(func):
    def wrapper(*args):
        print("[DEBUG]: function {}".format(func.__name__))
        return func(*args)

    return wrapper


@debug
def add(a, b):
    return a + b


add(1, 2)
# [DEBUG]: function add

有参装饰器

# 有参装饰器
def logging(level):
    def outer_wrapper(func):
        def inner_wrapper(*args, **kwargs):  # 参数在此
            print("[{}]: function {}".format(level, func.__name__))
            return func(*args, **kwargs)

        return inner_wrapper

    return outer_wrapper


# @logging(level="DEBUG")相当于先调用函数outer_wrapper=logging(level="DEBUG")得到@outer_wrapper
# @outer_wrapper相当于inner_wrapper=outer_wrapper(func)
# 最终执行inner_wrapper
@logging(level="DEBUG")
def add(a, b, *args):
    res = a + b
    for i in args:
        res += i
    return res


print(add(1, 2, 3, 4))
# [DEBUG]: function add
# 10

多重装饰器

自上而下,自下而上

def wrapper1(func):
    def inner1():
        print("inner1 before")
        func()
        print("inner1 after")

    return inner1


def wrapper2(func):
    def inner2():
        print("inner2 before")
        func()
        print("inner2 after")

    return inner2


def wrapper3(func):
    def inner3():
        print("inner3 before")
        func()
        print("inner3 after")

    return inner3


@wrapper1
@wrapper2
@wrapper3
def do():
    print("fun")


do()
# inner1 before
# inner2 before
# inner3 before
# fun
# inner3 after
# inner2 after
# inner1 after

生成器,generator

  • 生成器函数 生成器表达式

  • 含有yield关键字的函数为生成器函数,yield不可与return共用

def generator():
    a = '123456'
    for i in a:  # 一般写法
        yield i
    yield from a  # 简写


g = generator()
for i in g:
    print(i)
# 1
# 2
# 3
# 4
# 5
# 6
# 1
# 2
# 3
# 4
# 5
# 6

不给生成器传参

def generator():
    print("generator1")
    yield 'a'
    print("generator2")
    yield 'b'


result = generator()
print(result)
print(result.__next__())  # a
print(result.__next__())  # b
# print(result.__next__())  # StopIteration

# 生成器只能遍历一遍元素,获取完毕之后必须重新new
# 而对于列表来说,可以使用for i in l: print(i)遍历多次,但是生成器会报异常

给生成器传参

def generator():
    print(1)
    content = yield 'a'
    print(2, content)
    content = yield 'b'
    print(3, content)
    yield


g = generator()
print(g.__next__())
print(g.send("content1"))  # 需要给上一个yield位置传参,第一个需要用__next__,同理最后一个yield无法获取到值,不过可以yield空
print(g.send("content2"))
# 1
# a
# 2 content1
# b
# 3 content2
# None
def tractor():
    """
    拖拉机
    @return:
    """
    distance = 0
    second = 0
    avg_speed = 0
    while True:
        d, t = yield avg_speed
        distance += d
        second += t
        avg_speed = distance / second


avg = tractor()
print(avg.__next__())  # 0 摇车,人力启动柴油机
print(avg.send((10, 1)))  # 10.0
print(avg.send((12, 0.5)))  # 14.666666666666666
print(avg.send((10, 1)))  # 12.8

生成器嵌套

def generator():
    for i in range(4):
        yield i


g = generator()
g1 = (i for i in g)
print(g1, type(g1))
g2 = (i for i in g1)
print(g2, type(g2))
# print(list(g)) # 若此处注释打开你猜会如何
print(list(g1))  # [0, 1, 2, 3]
print(list(g2))  # [] 因为执行的时候g1只是一个能产生[0, 1, 2, 3]的迭代器,并不同于值本身
def add(a, b):
    return a + b


def nums():
    for i in range(4):
        yield i


g = nums()
for a in [1, 10]:
    g = (add(a, b) for b in g)  # 生成器表达式,不实际取元素的时候是不会列出元素的
print(list(g))  # [20, 21, 22, 23]

print(list((add(1, b) for b in nums())))  # [1, 2, 3, 4]
print(list((add(10, b) for b in nums())))  # [10, 11, 12, 13]
print(list((add(10, b) for b in (add(1, b) for b in nums()))))  # [11, 12, 13, 14]
print(list((add(10, b) for b in (add(10, b) for b in nums()))))  # [20, 21, 22, 23] 等价,a的值在list时才

你可能感兴趣的:(Python,python,开发语言)