Flask接口签名sign原理与实例代码浅析
253
2022-08-28
Python从门到精通(二):包装-01-函数的定义
py是一种类似介于面向对象和面向过程之间的一种语言,即有对象这样的高级概念,也会类似脚本语言的一些特性。本节主要聊下py的函数定义等知识点。
一、基础函数
1.1、函数的定义
虽然可以按脚本语言那样来定义函数,但在函数定义上还是比较建议不要采用隐藏参数的方式,参考代码如下:
_no_value = object()def default_func(a, b=0, c=None, d=_no_value): print(f"a={a} and b={b} and c={c} and d ={d}") if c is None: print("No b value supplied") return "RETUREN:" + str(a)# a=1 and b=0 and c=None and d =
1.2、函数的解析
有很多这样的元信息,下央只示例一种,代码如下:
def add(x:int, y:int) -> int: """注释""" return x + yprint(f'help info:\n {help(add)}')输出如下:Help on function add in module __main__:add(x: int, y: int) -> int 注释help info: None
print(f'annotations: {add.__annotations__}')#annotations: {'x':
1.3、函数的调用
py的函数调用也比较灵活,建议笔者在使用py函数功能时多从可读性方面着手选用合适的写法。
"""最普通的函数定义"""def greetUser(userName, age): """函数说明""" print (userName + "-" + str(age)); return "RETUREN:" + userName;greetUser("ld", 5);#位置 ld-5greetUser(userName="ld", age=5);#关键字 ld-5greetUser("ld", age=5);#ld-5
1.4、函数的参数
最简单的函数参数定义,可不定义参数类型也可以定义,带一个星号(*)参数的函数传入的参数存储为一个元组(tuple),带两个(*)号则是表示字典(dict)。如下:
def default_func(a:int) :
4.1.1、可选参数
以**开头的参数只能出现在最后一个参数中。*:类似于数组,**更倾向于map方式(在py中叫dict)。详细见下面代码:
"""定义任意数量0~n的参数,在函数内部会封装成元组信息"""def yuanzhuFun(*param): for item in param: print(item);yuanzhuFun("ld","hm"); #ld hm"""字典参数"""def mapFun(name, **param): for k, v in param.items(): print( k +":"+ v, end=',');mapFun("ld",color="green", age="5"); # color:green,age:5,
4.1.2、强制关键字调用
将强制参数放到某个以*开头或单个*号后面,这样调用者就必须用关键字来传递了,增加了代码的可读性;比**更直观,最好是放在单个*后面,也可以当必传参数来使用。
def recv(*, maxsize, block, test): #这种写法的话*,只是一个标识 return ''# recv(1024, True) # TypeErrorrecv(maxsize=1023, block=True, test=2)
def recv(*param, maxsize, block, test): #这种写法的话*,param是一个可选参数recv("ld",maxsize=1023, block=True, test=2)
#这种写法的话,在调用时后面必须要用关键字def logged(func=None, *, level=logging.DEBUG, name=None, message=None)
4.1.3、参数默认值
"""带默认值的函数定义,默认值的必须在后面"""def greetUserBydefault(userName, age=5): print( userName + "-" + str(age)); return "RETUREN:" + userName;greetUserBydefault("ld"); #位置 ld-5
参数动态默认值,其实就是用partial()函数来固化某些参数的值,防止参数过多时传错了。这个参数有两个作用,来解决代码兼容问题;
def test_func(a, b, c, d): return a, b, c, dfrom functools import partialtf_val_1 = partial(test_func, 1)print(f'partial 1: {tf_val_1(2, 3, 4)}') #(1, 2, 3, 4)tf_val_2 = partial(test_func, d=42)print(f'partial 42: {tf_val_2(1, 2, 3)}') #(1, 2, 3, 42)tf_val_3 = partial(test_func, 1, 2, d=42)print(f'not partial 4: {tf_val_3(4)}') #(1, 2, 4, 42)
1.5、函数值返回值
1.5.1、函数返回类型定义
def is_key(data: dict, key: str) -> bool: #指定函数返回值为bool,其它可选的有list, dict, int, str, set, tuple等
1.5.2、不显示指定返回值
def more_return_func(): return 1, 2, 3a, b, c = more_return_func()print(f'value of a = {a}') #value of a = 1print(f'value of b = {b}') #value of b = 2print(f'value of c = {c}') #value of c = 3print(f'more return: {more_return_func()}') #(1, 2, 3)
1.5.3、typing模块函数返回类型定义
这个模块可选的类型有Any、Union、Tuple、Callable、TypeVar、Generic等,类型检查,防止运行时出现参数和返回值类型不符合,该模块加入后并不会影响程序的运行,不会报正式的错误。typing也可以用在参数上面。
#元组def is_key(data: dict, key: Tuple[int]) -> None: print("")#全类型覆盖def is_key(data: dict, key: Any) -> Any: print("")
二、匿名函数
2.1、简单定义
add = lambda x, y: x + yprint(f'number add result = {add(2, 3)}') #5print(f"str add result: {add('hello', 'world')}") # hello world name_list = ['python', 'java', 'go', 'c++'] ['c++', 'go', 'java', 'python']print(f'sorted result: {sorted(name_list, key=lambda name: name.split()[-1].lower())}')
2.2、变量作用域
当内部函数对外部函数作用域的变量进行引用时,就会出现作用域的问题
x = 10a = lambda y: x + yx = 20b = lambda y: x + y#这处引用的x=20会被二次赋值覆盖掉print(f'a(20) = {a(20)}')#40print(f'b(20) = {b(20)}')#40#这里就各用各的值了x = 15print(f'when x=15,a(15) = {a(15)}')#30x = 3print(f'when x=3,a(15) = {a(15)}')#18#注意看x=x,这种定义时绑定的方式x = 10a = lambda y, x=x: x + yx = 20b = lambda y, x=x: x + yprint(f'a(15) = {a(15)}')#25print(f'b(15) = {b(15)}')#35
2.3、闭包
定义内部函数,如果想改变值需在sette函数中用nonlocal关键字
def test_func(): n = 0 def func(): print(f'var n = {n}') def get_n(): return n def set_n(value): nonlocal n #通过编写函数来修改内部变量的值 n = value # Attach as function attributes func.get_n = get_n func.set_n = set_n return funcf = test_func()f.set_n(10)print(f'get n is: {f.get_n()}') #10, nonlocal这行不加的话输出0
三、回调函数
3.1、有额外状态信息的回调函数
这种一般用于事件处理器,以及延时任务等,这里也有一个yield的使用(暂时可以不用理,简单点来讲就是一个性能提升的机制)。
def apply_async(func, args, *, callback): # Compute the result result = func(*args) # Invoke the callback with the result callback(result)def print_result(result): print(f'print result. Got: {result}')def add(x, y): return x + yapply_async(add, (3, 5), callback=print_result)apply_async(add, ('Hello ', 'World'), callback=print_result)#print result. Got: 8#print result. Got: Hello World
class ResultHandler: def __init__(self): self.sequence = 0 def handler(self, result): self.sequence += 1 print(f'result handler. [{self.sequence}] Got: {result}')r = ResultHandler()apply_async(add, (3, 5), callback=r.handler)apply_async(add, ('Hello ', 'World'), callback=r.handler)#result handler. [1] Got: 8#result handler. [2] Got: Hello World
def make_handler(): sequence = 0 def handler(result): nonlocal sequence sequence += 1 print(f'make handler. [{sequence}] Got: {result}') return handlerhandler = make_handler()apply_async(add, (3, 5), callback=handler)apply_async(add, ('Hello ', 'World'), callback=handler)#make handler. [1] Got: 8#make handler. [2] Got: Hello World
def make_handler(): sequence = 0 while True: result = yield sequence += 1 print(f'make handler use generator. [{sequence}] Got: {result}')handler = make_handler()next(handler)apply_async(add, (3, 5), callback=handler.send)apply_async(add, ('Hello ', 'World'), callback=handler.send)
3.2、内联回调函数
def apply_async(func, args, *, callback): # Compute the result result = func(*args) # Invoke the callback with the result callback(result)from queue import Queuefrom functools import wrapsclass Async: def __init__(self, func, args): self.func = func self.args = argsdef inlined_async(func): @wraps(func) def wrapper(*args): f = func(*args) result_queue = Queue() result_queue.put(None) while True: result = result_queue.get() try: a = f.send(result) apply_async(a.func, a.args, callback=result_queue.put) except StopIteration: break return wrapperdef add(x, y): return x + y@inlined_asyncdef test(): result = yield Async(add, (3, 5)) print(f'number add result: {result}') result = yield Async(add, ('Hello ', 'World')) print(f'str add result: {result}') for n in range(10): result = yield Async(add, (n, n)) print(f'async cycle result: {result}') print('Goodbye')if __name__ == '__main__': import multiprocessing pool = multiprocessing.Pool() apply_async = pool.apply_async test() number add result: 8str add result: Hello Worldasync cycle result: 0async cycle result: 2async cycle result: 4async cycle result: 6async cycle result: 8async cycle result: 10async cycle result: 12async cycle result: 14async cycle result: 16async cycle result: 18Goodbye
附、将类转换为函数(简化代码)
from urllib.request import urlopenclass UrlTemplate: def __init__(self, template): self.template = template def open(self, **kwargs): return urlopen(self.template.format_map(kwargs))bai_du = UrlTemplate('line in bai_du.open(name_list='python,java,go', field_list='1'): print(line.decode('utf-8'))
"""与上面代码等价"""def url_template(template): def opener(**kwargs): return urlopen(template.format_map(kwargs)) return opener #注意这行是返回一个函数bai_du = url_template('line in bai_du(name_list='python,java,go', field_list='1'): print(line.decode('utf-8'))
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~