Python基础(6)——函数和lambda表达式(下)

5. 函数的高级用法

5.1 局部函数(嵌套函数)

python中允许在函数体内部定义函数,这种被放在函数体内定义的函数称为局部函数,又称为嵌套函数。

def outer_func():
    name = "Meng"
    def inner_func():
        print(name)
    inner_func()
outer_func()

5.2 高阶函数

一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数,满足其一则为高阶函数。

# example
# 函数作为参数传递给另外一个函数
def get_two_sum(x, y):
    return x + y
def print_two_sum(func, a, b):
    result = func(a, b)
    print("两个数的结果为:", result)
print_two_sum(get_two_sum, 10, 20)
#======output========
两个数的结果为: 30
# 函数作为返回值
def returned_func():
    print("returned_func函数被调用")
def outer_func():
    print("outer_func函数被调用")
    return returned_func
ret = outer_func()
ret()
#=======output=======
outer_func函数被调用
returned_func函数被调用

常用的高阶函数包括map()、filter()、reduce(),常常和lambda表达式一起使用,使用方式如下:

map()函数

该函数接收的是两个参数,一个函数,一个序列,其功能是将序列中的值做出处理后依次返回给序列,它的返回值是一个迭代器对象。

list1 = [1, 2, 3, 4]
list2 = list(map(lambda x: x**2, list1)) # 将列表中的元素变成对应元素的平方,这里第二个参数传入一个元组、字符串也是可以的,如果传入的是字典类型,需要将其变成dict_items类型
print(list2)
#========output========
[1, 4, 9, 16]

filter()函数

该函数同样接收的是两个参数,一个函数和一个序列,其功能是过滤。其返回值也是一个迭代器对象。

list1 = [1, 2, 3, 4]
list2 = list(filter(lambda x: x % 2 == 0, list1)) # 过滤出的是函数返回值是True的元素
print(list2)
#=======output========
[2, 4]

reduce()函数

该函数也是接收三个参数,一个是函数,一个是序列,还有一个可选参数是一个初始值,其功能是对参数序列中的元素进行累积,其返回值是一个值。它不是内置函数,是functools模块中的函数。

from functools import reduce
list1 = [1, 2, 3, 4]
result = reduce(lambda x, y: x + y, list1, 10)
print(result)
#=======output=======
20
# 其计算过程如下
# 10 + 1 = 11
# 11 + 2 = 13
# 13 + 3 = 16
# 16 + 4 = 20

5.3 函数的闭包

利用嵌套函数,在外部函数中定义一个内部函数,内部函数中运用了外部函数中的临时变量,并且外部函数的返回值是内部函数的引用,这样就形成了一个闭包。

def outer_func(a):
    b = 10
    def inner_func():
        return a + b
    return inner_func
ret = outer_func(3)
print(ret())

5.4 函数装饰器

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

装饰器=高阶函数+函数嵌套+闭包

5.4.1 无参函数装饰器

首先是最简答的装饰器,要装饰的函数不需要额外的参数,例如测试一个函数执行的时间:

import time
def test_run_time(func): # 函数作为参数,形成高阶函数
    def wrapper(): # 函数内部定义函数,形成函数嵌套
        start_time = time.time()
        func() # 使用外层函数变量,形成闭包
        end_time = time.time()
        print("函数运行时间为:", end_time - start_time)
    return wrapper # 函数作为返回值,形成高阶函数
@test_run_time  # 该语法就相当于 test = test_run_time(test) 简化了操作,省去了一个赋值语句。
def test():
    time.sleep(1)
    print("这里是要测试的函数")
test()

5.4.2 有参函数装饰器

import time
def test_run_time(func):
    def wrapper(*args): # 如果要装饰的函数不需要传关键字参数,则只写*args就可以,如果需要关键字参数,需要加上**kwargs
        start_time = time.time()
        func(*args)
        end_time = time.time()
        print("函数运行时间为:", end_time - start_time)
    return wrapper
@test_run_time
def print_two_sum(a, b):
    time.sleep(1)
    print("{}+{}={}".format(a, b, a+b))
print_two_sum(5, 7)
#=========output=========
5+7=12
函数运行时间为: 1.0009658336639404

5.4.3 有返回值函数装饰器

import time
def test_run_time(func):
    def wrapper(*args):
        start_time = time.time()
        result = func(*args)
        end_time = time.time()
        print("函数运行时间为:", end_time - start_time)
        return result
    return wrapper
@test_run_time
def get_two_sum(a, b):
    time.sleep(1)
    return a + b
result = get_two_sum(5, 7)
print("两数之和为:", result)
#=======output=======
函数运行时间为: 1.0006444454193115
两数之和为: 12

根据上面三个例子我们就可以总结出一个完整的装饰器框架如下:

def wrap(func):
    def wrapper(*args, **kwargs):
        """可增加功能"""
        result = func(*args, **kwargs)
        """可增加功能"""
        return result
    return wrapper

在使用时只需在定义函数前面加上@wrap即可。

5.4.4 带参数的装饰器

使用了两层嵌套函数,相当于对原有装饰器进行封装,并返回一个装饰器。

import time
def cal(mark):
    def wrapper(func):
        def deco(*args):
            if mark == "+":
                print("这是加法运算")
            elif mark == "*":
                print("这是乘法运算")
            start_time = time.time()
            result = func(*args)
            end_time = time.time()
            print("{}运算耗时:".format(mark), end_time - start_time)
            return result
        return deco
    return wrapper

@cal("+")	# 该语法就相当于 cal = cal("+")  get_two_sum = cal(get_two_sum)
def get_two_sum(a, b):
    time.sleep(1)
    return a + b

@cal("*")
def get_two_multi(a, b):
    time.sleep(2)
    return a * b
result = get_two_sum(5, 7)
print("两数之和为:", result)
print('-' * 20)
result1 = get_two_multi(5, 7)
print("两数之积为:", result1)
#===========output=========
这是加法运算
+运算耗时: 1.0009543895721436
两数之和为: 12
--------------------
这是乘法运算
*运算耗时: 2.0008320808410645
两数之积为: 35

5.5 偏函数

当一个函数有很多参数时,调用者就需要提供多个参数。如果减少参数个数,就可以简化调用者的负担。使用偏函数可以将函数中的某个或某些参数固定,这样在需要传相同参数的情况下就可以少写一个参数,减轻负担。该功能通过调用functools中的partial来实现。

# example
# 例如要将多个二进制字符串转换成数字,我们可以进行如下操作,省去了在每次调用时都要传入base参数的麻烦
from functools import partial
int2 = partial(int, base=2)
print(int2("11001"))

5.6 生成器函数

生成器函数(Generator)是一种特殊的函数,是用来创建生成器对象的工具,生成器函数使用yield语句返回。其返回值是一个生成器对象。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行。

# 使用生成器生成斐波那契数列
def fib(num):
    a, b = 0, 1
    for i in range(num):
        yield b
        a, b = b, a+b
for i in fib(10):
    print(i, end=" ")
#========output=======
1 1 2 3 5 8 13 21 34 55 

生成器只能遍历一次

生成器表达式

类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表。

# 列表推导式
list1 = [i for i in range(0, 10, 2)]
for i in list1:
    print(i)
# 在使用for循环遍历后再对其进行访问,仍然可以访问
print(list1[2])

# 生成器表达式
gen = (i for i in range(0, 10, 2))
for i in gen:
    print(i)
# 在使用for循环遍历完后对其中单个元素进行访问,不能访问
print(gen[2]) # TypeError: 'generator' object is not subscriptable
# 这说明,生成器表达式在调用完一次之后就被销毁了

生成器与迭代器虽然在使用方式上类似,但是内部的原理却完全不相同。

  1. 迭代器是所有的内容都在内存上, 使用next函数往下遍历

  2. 生成器不会把内容放在内存里,每次调用next函数时,返回的都是计算出来的那个元素,用完后立即销毁。

所以使用生成器与迭代器存在时间上与空间上的衡量,如果是数据量较大的程序,那么使用生成器,但是如果是时间至上,则可以优先考虑迭代器。

参考自博客https://blog.csdn.net/qq_20880939/article/details/100899942

6. Python中的内置函数

内置函数
abs()delattr()hash()memoryview()set()
all()dict()help()min()setattr()
any()dir()hex()next()slice()
ascii()divmod()id()object()sorted()
bin()enumerate()input()oct()staticmethod()
bool()eval()int()open()str()
breakpoint()exec()isinstance()ord()sum()
bytearray()filter()issubclass()pow()super()
bytes()float()iter()print()tuple()
callable()format()len()property()type()
chr()frozenset()list()range()vars()
classmethod()getattr()locals()repr()zip()
compile()globals()map()reversed()__import__()
complex()hasattr()max()round()

点击对应函数名查看相应用法。

7. 其它

7.1 对函数的参数和返回值类型的指定和检查

Python在3.5版本之后加入了对参数和返回值类型的指定和检查,在新建变量时也可以指定类型。

7.1.1 基本类型的指定

def test(a: str) -> list:
    return a

test([1, 2, 2])

例如,我们在上面函数中指定a的类型为字符串,返回值类型为list,在代码中直接将a作为返回值返回,在pycharm中使用的时候它会给出相应的颜色提示,但是在实际运行的时候是不会报错的,因为Python的本质是动态语言。

7.1.2 复杂的指定(集合相关类型的指定)

除了最基本的数据类型指定,还可以进行集合相关类型的指定。

这里需要用到typing模块中的一些类和方法

from typing import List
Vector = List[float] # 这样就指定了List中的元素需为float类型,如果里面指定每个元素的类型如:Tuple[float, int], 那么它的长度就只能是2,并且,第一个元素为float类型,第二个元素为int类型,当然也是只会在pycharm中给出提示,实际运行并不会因为检查类型不匹配报错。
def scale(scalar: int, vector: Vector) -> Vector:
    return [scalar * num for num in vector]
new_vector = scale(2, [1.0, 2.6, 5.4])
print(new_vector)

7.1.3 泛型的指定

from typing import Sequence, TypeVar, Union
T = TypeVar('T')      # 声明一个类型变量,如果后面什么都不加,那么就可以是任意类型
def first(l: Sequence[T]) -> T:
    return l[0]

如果在声明类型变量的时候,后面指定可以表示哪些类型,那么在检查的时候会进行匹配,如果不匹配会给出相应提示。

T = TypeVar('T')  # T可以表示任何类型
A = TypeVar('A', str, bytes)  # A必须是字符串或字节

7.1.4 创建变量时的类型指定

name:str = "Meng" # 如果写成 name:str = 123,pycharm将会给出提示
print(name)

在这里插入图片描述

其它更多的类型指定可以参考Pythontyping说明文档

该部分内容参考自博客https://blog.csdn.net/sgyuanshi/article/details/96192887

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值