博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Python基础 - 06函数高级

Posted on 2021-10-10 16:56  Kingdomer  阅读(23)  评论(0编辑  收藏  举报

Python函数 - 06函数高级

一、函数嵌套

在函数里面还可以定义函数,可以嵌套多层,执行需要被调用

def outer():
    a = 100

    def inner():
        b = 200
        print('内部函数inner')

    print(a)
    print(inner)

outer()
'''
100
<function outer.<locals>.inner at 0x0000001552A0B310>
'''

 

locals() 查看函数中的局部变量  

def outer():
    a = 100

    def inner():
        b = 200
        print('内部函数inner')

    result = locals()  # locals()表示查看函数中的局部变量,以字典形式返回
    print(result)

outer()   # {'a': 100, 'inner': <function outer.<locals>.inner at 0x0000000DC2DCB430>}

  

def outer2():
    a = 100

    def inner2():
        b = 200
        b += a        #  内部函数可以直接使用外部函数的变量
        print('内部函数inner2, a =', a)
        print('内部函数inner2, b =', b)

    print(a)
    inner2()

outer2()
# 100
# 内部函数inner2, a = 100
# 内部函数inner2, b = 300

  

内部函数对外部函数的变量进行修改、计算

def outer2():
    a = 100

    def inner2():
        b = 200
        # b += a       内部函数可以直接使用外部函数的变量
        nonlocal a
        a += b
        print('内部函数inner2, a =', a)

    print(a)
    inner2()

outer2()
# 100
# 内部函数inner2, a = 300

 

全局变量  

a = 100
def outer3():
    a = 200
    def inner3():
        a = 300
        print('内部函数inner3, a =',a)
        a -= 50
    print('函数outer3, a =',a)
    inner3()
outer3()
print('变量, a =',a)
# 函数outer3, a = 200
# 内部函数inner3, a = 300
# 变量, a = 100

  

a = 100

def outer4():
    a = 200

    def inner4():
        # a = 300
        global a  
        a -= 50
        print('内部函数inner4,a =', a)

    print(a)  
    inner4()

outer4()    
print(a)   
# SyntaxError: name 'a' is assigned to before global declaration
# 将 a = 300 注释掉
# 200
# 内部函数inner4,a = 50
# 50

  

# 内层函数 -->  外层函数 -->  全局变量 --> 系统 builtins

a = 100

def outer4():
    a = 200

    def inner4():
        nonlocal a
        a -= 50
        print('内部函数inner4,a =', a)

    print(a)        # 200
    inner4()

outer4()            # 内部函数inner4,a = 150
print(a)            # 100

  

二、闭包

1. 嵌套函数 2. 内部函数引用了外部函数的变量 3. 返回值是内部函数
闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数块+引用环境)

def outer5(n):
    a = 10
    def inner5():
        b = a + n
        print('内部函数inner5, b =', b)
    return inner5

r = outer5(5)
print(r)             # <function outer5.<locals>.inner5 at 0x000000A11196B670>
r()                  # 内部函数inner5, b = 15

  

函数inner5是函数outer5的内嵌函数,并且inner5函数是outer5函数的返回值。

内嵌函数inner5引用到外层函数中的局部变量n, 每次调用outer5函数都将生成并保存一个新的局部变量n, 这里outer5函数返回的就是闭包。

在一个内部函数里,对在外部作用域(但不是全局作用域)的变量进行了引用,那么内部函数就被认为是闭包(closure)。

 

三、 装饰器

定义一个变量指向函数

def foo():
    print('foo')
def bar():
    print('bar')

foo = bar
foo()        # bar 

 

函数名仅仅是个变量,只不过指向了定义的函数而已,所以才能通过函数名() 调用,

如果 函数名 = xxx 被修改了,那么当执行函数名()时,调用的就不是之前的那个函数了。

3.1 装饰器: 遵循开放封闭原则,再不改变原函数的情况下,扩展了函数功能。

使用场景:  引入日志、 函数执行时间统计、 执行函数前预备处理、 执行函数后清理功能、 权限校验等场景、 缓存

# 定义,格式
def aaa(func): def xxx(参数,...): ... func() ... return yyy return xxx @aaa def zzz(): pass

  

def decorator(func):
    def wrapper():
        func()
        print('刷漆')
        print('铺地板')

    return wrapper

@decorator                # house = decorator(house) -> func=house -> house=wrapper
def house():
    print('毛坯房....')

house()

 

装饰器执行过程:  

def outer_checker(time):
    print('----------->1')
    def check_time(action):
        print('----------->2')
        def do_action():
            print('----------->3')
            if time < 22:
                return action()
            else:
                return '没有权限'
        print('----------->4')
        return do_action
    print('------------>5')
    return check_time

@outer_checker(21)
def play_game():
    print('----------->6')
    return '玩游戏'

print(play_game())

# outer_checker(21)
----------->1
------------>5
----------->2
----------->4
----------->3
----------->6
玩游戏

# outer_checker(23)   r=outer_checker(23)  r=check_time -> check_time(play_game)  -> play_game=do_action
----------->1
------------>5
----------->2
----------->4
----------->3
没有权限

 

装饰器带普通参数

# 带参数的装饰器
def decorator2(func):
    def wrapper(address):
        func(address)
        print('刷漆')
        print('地板')

    return wrapper

@decorator2
def house2(address):
    print('房子地址在{},是毛坯房'.format(address))

house2('北京')

  

装饰器带可变参数args, kwargs

def decorator3(func):
    def wrapper(*args):
        func(*args)    # args是一个元祖, func=house3, func(('老郭','北京',80))
        print('刷漆')
        print('地板')

    return wrapper


@decorator3
def house3(name, address, area=40):
    print('客户{}房子地址在{},是毛坯房,面积是{}'.format(name, address, area))


house3('老郭', '北京', 80)

  

def decorator4(func):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)
        print(kwargs)
        print('刷漆')
        print('地板')

    return wrapper


@decorator4
def house4(name, address, area=40, price=40, year=2019):
    print('客户{}房子地址在{},是毛坯房,面积是{},竣工在{}年,花了{}万元'.format(name, address, area, year,price))

laoguo={'address':'北京', 'area':80}
house4('老郭', **laoguo)  

 

装饰器中的return

def decorator5(func):
    def wrapper(*args, **kwargs):
        r = func(*args, **kwargs)
        print('装修费用为:{}元'.format(r))
        print('刷漆')
        print('地板')
        return 6000

    return wrapper

@decorator5
def house5(name, address, area=40, price=40, year=2019):
    print('客户{}房子地址在{},是毛坯房,面积是{}'.format(name, address, area))
    return 5000

a = house5('老郭', '北京',60,44)       # 装修费用为:5000元
print(a)                              # 6000

  

四、递归函数

def a():
    print('---------aaa-------------')
    a()

# a() # RecursionError: maximum recursion depth exceeded while calling a Python object

  

# 打印 1 - 10
def p_num(i):
    if i == 10:
        print('10')
    else:
        print(i)
        i += 1
        p_num(i)

p_num(1)

# 计算 1+2+...+9+10
def c_num(i):
    if i == 10:
        return 10
    else:
        return i + c_num(i + 1)

c = c_num(1)
print(c)                        # 55

# 阶乘:  1*2*3*4*...*n
def cal(n):
    if n == 1 or n == 2:
        return n
    else:
        return n * cal(n - 1)

c = cal(5)
print(c)

  

五、 匿名函数

用lambda关键字创建小型匿名函数。 这种函数得名于省略了用def声明函数的标准步骤。

Lambda函数的语法只包含一个语句, 格式为: lambda 参数列表: 运算表达式

def test(a):
    return a + 1

r = lambda a: a + 1
print(test) # <function test at 0x000000118E099390> print(r) # <function <lambda> at 0x000000118E088430> print(r(8)) # 9

  

六、高阶函数

在Python中, 函数也是一种数据类型。函数对应的数据类型为 function, 可以把它当做数字或字符串来处理。

函数可以接收另一个函数作为参数,也可以把一个函数当做另一个函数的返回值,这种函数的使用方式称为高阶函数。

 

6.1 函数作为另一个函数的参数

# -- 传统方式
def test():
    print('----test---------')

def func(a, f):
    print('------>', a)
    f()

func(3, test)  # ------> 3   \n  ----test---------

# -- Lambda表达式
def test1(n, f):
    print('------>', n)
    r = f(n)
    print('------>', r)

test1(9, lambda x: x ** 2)

  

6.2 Python中使用函数作为参数的内置函数和类

sorted函数: 用来将一个无序列表进行排序, 函数参数的返回值规定按照元素的哪个属性进行排序

m = max(5, 9)
print(m)                          # 9
m = max([2, 4, 56, 8, 88, 33])
print(m)                          # 88
list1 = [('tom', 19), ('jack', 20), ('xi', 99), ('mm', 15)] m = max(list1, key=lambda x: x[1]) print(m) # ('xi', 99) m = min(list1, key=lambda x: x[1]) print(m) # ('mm', 15) s = sorted(list1, key=lambda x: x[1], reverse=True) print(s) # [('xi', 99), ('jack', 20), ('tom', 19), ('mm', 15)]

  

filter类:     用来过滤一个列表里符合规定的所有元素,得到的结果是一个迭代器,函数参数的返回值指定元素满足的过滤条件。

map类:        将列表里的每一项数据都执行相同的操作,得到一个迭代器, 函数参数用来指定列表里元素所执行的操作。

reduce函数:   对一个序列进行压缩算法,得到一个值。python3,方法移动到functools模块, 函数参数用来指定按照哪种方式合并。

list1 = [('tom', 19), ('jack', 20), ('xi', 99), ('mm', 15)]
# filter的匿名函数要求返回值必须是bool类型,只有bool类型结果为True才是符合过滤条件的
rr = filter(lambda x: x[1] > 20, list1) print(rr) # <filter object at 0x000000516B500430> print(list(rr)) # [('xi', 99)]
# 通过匿名函数指明提取的内容,并对内容进行加工 map = map(lambda x: x[1] + 1, list1) print(map) # <map object at 0x0000003B1B4F03A0> print(list(map)) # [20, 21, 100, 16] print(list1) # 不变
map1 = map(lambda x: x[0].title(), list1) print(list(map1)) # ['Tom', 'Jack', 'Xi', 'Mm']

 

# 对map迭代器的处理只能一次,处理之后map1 不存在

list1 = [('tom', 19), ('jack', 20), ('xi', 99), ('mm', 15)]
map1 = map(lambda x: x[1], list1)
print(list(map1))     # [19, 20, 99, 15]
print(list(map1))     # [] 

  

from functools import reduce

list1 = [('tom', 19), ('jack', 20), ('xi', 99), ('mm', 15)]

map1 = map(lambda x: x[1], list1)
list2 = list(map1)
print(list2)                 # [19, 20, 99, 15]

red = reduce(lambda x, y: x + y, list2)
print(red)                   # 153