Self-study Python Fish-C Note15 P52to53

发布于:2024-08-13 ⋅ 阅读:(83) ⋅ 点赞:(0)

函数 (part 5)

本节主要讲函数文档、类型注释、内省、高阶函数

函数文档、类型注释、内省 (P52)

函数文档

函数是一种代码封装的方法,对于一个程序来说,函数就是一个结构组件。在函数的外部是不需要关心函数内部的执行细节的,更需要关注的是函数的接口以及执行后的结果。要学会去阅读开发手册和函数文档,以快速的融入一个项目
在 python 中,我们可以使用 help() 函数,快速的查看到一个函数的使用文档:

help(print)
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.
# 详解:
# Help on built-in function print in module builtins:

# print(...)
#     print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) # 展示了 print 函数的原型
    
#     Prints the values to a stream, or to sys.stdout by default. # 函数的功能介绍
#     Optional keyword arguments:  # 各个参数的类型及作用
#     file:  a file-like object (stream); defaults to the current sys.stdout.
#     sep:   string inserted between values, default a space.
#     end:   string appended after the last value, default a newline.
#     flush: whether to forcibly flush the stream.

如何创建函数文档,使用 """

def exchange(dollar, rate=6.32):
    """
    功能:汇率转换,美元->人民币
    参数:
    ·dollar 美元数量
    ·rate 汇率,默认值是 6.32 (2022-03-08)
    返回值:
    ·人民币数量
    """
    return dollar * rate
exchange(20)
126.4
help(exchange)
Help on function exchange in module __main__:

exchange(dollar, rate=6.32)
    功能:汇率转换,美元->人民币
    参数:
    ·dollar 美元数量
    ·rate 汇率,默认值是 6.32 (2022-03-08)
    返回值:
    ·人民币数量

注意:函数文档一定是要在函数的最顶部的。

类型注释

示例:
比如以下函数,作者希望调用者传入到a参数中的类型是字符串类型,b参数的类型是整数类型,这个函数的返回值将是一个字符串类型。

def func(a:str,b:int) -> str:
    return a*b
func(a='n',b=3)
'nnn'

但是这并不是强制的。Python 运行时不强制执行函数和变量类型注解,但这些注解可用于类型检查器、IDE、静态检查器等第三方工具。(即并不是设置类型后像 java 那样的强类型定义语言了)。如:

func(3,5)
15

如果我们要设置默认参数:

def func(a:str='e',b:int=5) -> str:
    return a*b
func()
'eeeee'

如果说我们期待的参数类型是列表,甚至一个整数列表(所有值都是整数的列表)

def func(a:list,b:int=3) -> list:
    return a*b
func([1,2,3])
[1, 2, 3, 1, 2, 3, 1, 2, 3]
def func(a:list[int],b:int=3) -> list:
    return a*b
func([1,2,3])
[1, 2, 3, 1, 2, 3, 1, 2, 3]

映射类型也可实现,比如我们期待的字典的键是字符串,而值是整数

def func(a:dict[str,int],b:int=3) -> list:
    key = list(a.keys())*b
    v = list(a.values())*b
    res=key+v
    return res
func({"a":1,'b':2,'c':3})
['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 1, 2, 3, 1, 2, 3, 1, 2, 3]

如果我们想让python帮我们做一下检测,可以使用 Mypy 模块

内省

在程序运行的时候能够进行自我检测的一种机制,称之为内省或自省
Python 是通过一些特殊的属性来实现内省的:
求知一个函数的名字

exchange.__name__
'exchange'

求知一个函数的类型注释

func.__annotations__
{'a': dict[str, int], 'b': int, 'return': list}

查看函数文档

exchange.__doc__
'\n    功能:汇率转换,美元->人民币\n    参数:\n    ·dollar 美元数量\n    ·rate 汇率,默认值是 6.32 (2022-03-08)\n    返回值:\n    ·人民币数量\n    '
print(exchange.__doc__)
    功能:汇率转换,美元->人民币
    参数:
    ·dollar 美元数量
    ·rate 汇率,默认值是 6.32 (2022-03-08)
    返回值:
    ·人民币数量

高阶函数 (higher-order function) (P53)

当一个函数接收另一个函数作为参数的时候,那么这个时候这种函数就叫高阶函数
其实在前面的装饰器那一节我们就碰到过高阶函数

# 前面装饰器的例子
import time 
def time_master(func):
    def call_func():
        print('start')
        start = time.time()
        func()
        stop = time.time()
        print('stop')
        print(f'In total we used {(stop-start):.2f} second')
    return call_func

def myfunc():
    time.sleep(2)
    print('Hi')
    
myfunc = time_master(myfunc)
myfunc()
start
Hi
stop
In total we used 2.00 second

在这里 time_master()myfunc() 作为参数使用,time_master()就是一个高阶函数。
Pyhton 中常见的高阶函数有 map, filter, 除此外min, max, salty也可以算是高阶,因为他们有一个 key 参数接收的就是一个函数对象。

functools 模块

Python 中收集实用的一些高阶函数以及装饰器的模块

reduce() 函数

reduce() 函数有两个参数,第一个参数是一个函数,第二个参数是一个可迭代对象。

def add_f(a,b):
    return a+b
import functools
functools.reduce(add_f, [1,2,3,4,5])
15

这里 reduce 的作用就是将可迭代对象中的元素依次传递到第一个参数指定的函数中,最终返回累积的结果。
其实就相当于:

add_f(add_f(add_f(add_f(1,2),3),4),5)
15

reduce() 函数的第一个参数是一个函数,自然也可以是 lambda 表达式。比如计算10的阶乘:

functools.reduce(lambda x,y:x*y, range(1,11))
3628800
偏函数

偏函数是指对指定的函数进行二次包装,通常是对现有的函数部分参数预先绑定,从而得到一个新的函数,则该函数称之为偏函数。
偏函数通过 functools 里的 partial 来实现
偏函数的作用就是将一个函数的多个参数给拆分多次进行传递。如:

square = functools.partial(pow,2)
print(square(2))
print(square(3))
print(square(5))
4
8
32
cube = functools.partial(pow,3)
print(cube(2))
print(cube(3))
print(cube(5))
9
27
243

和我们之前讲到闭包一样实现这个功能,其实这个偏函数的实现原理就是闭包。

@wraps

我们回到前面装饰器 time_mastermyfunc 的例子:

def time_master(func):
    def call_func():
        print('start')
        start = time.time()
        func()
        stop = time.time()
        print('stop')
        print(f'In total we used {(stop-start):.2f} second')
    return call_func

@time_master
def myfunc():
    time.sleep(2)
    print('Hi')
    
myfunc()
start
Hi
stop
In total we used 2.01 second

但是这里有一个副作用,调用myfunc.__name__ 会得到 'call_func' 而不是 myfunc

myfunc.__name__
'call_func'

装饰器其实是一个语法糖,代码其实相当于:

def time_master(func):
    def call_func():
        print('start')
        start = time.time()
        func()
        stop = time.time()
        print('stop')
        print(f'In total we used {(stop-start):.2f} second')
    return call_func

def myfunc():
    time.sleep(2)
    print('Hi')
    
myfunc = time_master(myfunc)
myfunc()
start
Hi
stop
In total we used 2.01 second

由于闭包的设计,调用 myfunc 函数其实是调用了 time_master 函数,然后传入 myfunc 作为其参数。而调用 time_master 函数其实是调用 call_func 函数。所以当使用 name 属性内省的时候,就是 call_func 了。
其实实际运用的时候影响不大,但是如果想纠正这个问题,可以用 @wraps 装饰器来装饰装饰器。

def time_master(func):
    @functools.wraps(func)
    def call_func():
        print('start')
        start = time.time()
        func()
        stop = time.time()
        print('stop')
        print(f'In total we used {(stop-start):.2f} second')
    return call_func

def myfunc():
    time.sleep(2)
    print('Hi')
    
myfunc = time_master(myfunc)
myfunc()
start
Hi
stop
In total we used 2.00 second
myfunc.__name__
'myfunc'
# 或者装饰器的形式
def time_master(func):
    @functools.wraps(func)
    def call_func():
        print('start')
        start = time.time()
        func()
        stop = time.time()
        print('stop')
        print(f'In total we used {(stop-start):.2f} second')
    return call_func

@time_master
def myfunc():
    time.sleep(2)
    print('Hi')
    
myfunc()
start
Hi
stop
In total we used 2.01 second
myfunc.__name__
'myfunc'

附言:
题目:Self-study Python Fish-C Note-15 P52-P53
本文为自学B站上鱼C的python课程随手做的笔记。一些概念和例子我个人为更好的理解做了些查询和补充
因本人水平有限,如有任何问题,欢迎大家批评指正!
原视频链接:https://www.bilibili.com/video/BV1c4411e77t?p=8


网站公告

今日签到

点亮在社区的每一天
去签到