下面是python中函数的几点高阶技巧,欢迎各位指正
构造可接受任意参数数量的函数
可接受任意数量的位置参数和关键字参数
def func(*args,**kwargs): print("args=",args) print("kwargs=",kwargs) print(type(args)) #元组类型 print(type(kwargs)) #字典类型 def a(x, *args, y): pass def b(x, *args, y, **kwargs): pass
- 所有的位置参数放入args种,所有的关键字参数放入kwargs中
- 一个星参数只能出现在最后一个位置参数后面,两个星参数只能出现在最后一个参数位置上
- 一个星参数之后可以添加任意类型的参数
只接受关键字参数的函数
def recv(maxsize, *, block): 'Receives a message' pass recv(1024, True) # TypeError recv(1024, block=True) # Ok def mininum(*values, clip=None): m = min(values) if clip is not None: m = clip if clip > m else m return m minimum(1, 5, 2, -5, 10) # Returns -5 minimum(1, 5, 2, -5, 10, clip=0) # Returns 0
- 可以直接放在*号后面
- 可以在接受完多个位置参数外,指定关键字参数
- 使用强制关键字参数比直接使用kwargs要清晰许多
返回多个值的函数
- 可以使用return 返回一个元组即可,再进行后续的拆包之类的操作
定义有默认参数的函数
可以直接将默认参数放置在函数参数的最后即可
def spam(a, b=42): print(a, b) # Using a list as a default value def spam(a, b=None): if b is None: b = [] x=80 def func(a,b=x): #函数的默认值只在函数定义时,赋值一次终止 print(a) print(b) func(1) #返回a=1,b=80 x=20 func(1) #返回a=1,b=80,不变 func(2,20) #返回a=2,b=20 再次传参才可以改变 def spam(a, b=None): if not b: # NO! Use 'b is None' instead b = []
如果函数的默认参数是一个列表,集合或字典,可使用None作为默认值传进参数中
注意函数的默认参数应该是是不可变类型,不要在函数定义时,传入列表之类的可变参数
当设默认参数为None时,注意使用is None来判断参数是否为空,不要使用not b,这样会导致长度为0的字符串列表i之类的全部当作None来处理
怎么来解决参数None判断非空的问题呢:
no_value=object() def func(a,b): if b is no_value: print("no b value supplied!") pass
- 定义object类,因为object类是所有类的基类,创建它的实例,没有任何影响,实例对象没有任何的属性,只是当作同一性的验证而已,可以解决参数为空问题的判断
定义匿名或或内联函数
names = ['David Beazley', 'Brian Jones', 'Raymond Hettinger', 'Ned Batchelder'] sorted(names, key=lambda name: name.split()[-1].lower()) '''返回结果显示如下: ['Ned Batchelder', 'David Beazley', 'Raymond Hettinger', 'Brian Jones']'''
- 使用lambda匿名函数可以快速创建简短函数
匿名函数捕获变量值
特别注意,lambda函数的参数是自由变量,不是定义时就绑定好的,而是在运行时绑定
x = 10 a = lambda y: x + y x = 20 b = lambda y: x + y a(10) #30 b(20) #30
- lambda函数在运行时绑定变量参数
如何捕获呢?:
x = 10 a = lambda y, x=x: x + y #在定义时,将参数值设定为默认参数即可捕获变量的值 x = 20 b = lambda y, x=x: x + y a(10) #20 b(10) #30
- 使用默认参数的形式,即可在lambda函数定义时绑定该变量参数
将单方法的类转换为函数
除了__init__方法外,只有一个方法的类,想将其转换为函数:
from urllib.request import urlopen class UrlTemplate: #打开某个网址 def __init__(self, template): self.template = template def open(self, **kwargs): return urlopen(self.template.format_map(kwargs)) # Example use. Download stock data from yahoo yahoo = UrlTemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}') for line in yahoo.open(names='IBM,AAPL,FB', fields='sl1c1v'): print(line.decode('utf-8')) #—————————————————上述类可转换为一个函数—————————————————————— def urltemplate(template): #使用闭包将单方法类转换为函数 def opener(**kwargs): return urlopen(template.format_map(kwargs)) return opener # Example use yahoo = urltemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}') for line in yahoo(names='IBM,AAPL,FB', fields='sl1c1v'): print(line.decode('utf-8'))
- 一个闭包就是一个函数,是内部函数带有额外状态的函数,闭包可以记住函数本身定义时的环境变量
- 在上述代码中,opener记住了template变量的状态
带有额外状态信息的回调函数
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('Got:', result) def add(x, y): return x + y apply_async(add, (2, 3), callback=print_result) #Got: 5 apply_async(add, ('hello', 'world'), callback=print_result) #Got: helloworld
注意print_result函数只有一个参数result,无法返回更多关于内部函数的相关信息
怎样让回调函数访问外部信息呢?:
使用绑定方法,代替一个简单函数
class ResultHandler: def __init__(self): self.sequence = 0 #当每次调用handler方法时,sequence自加1 def handler(self, result): self.sequence += 1 print('[{}] Got: {}'.format(self.sequence, result)) r = ResultHandler() #创建实例对象 apply_async(add, (2, 3), callback=r.handler) #调用实例方法handler,序列加1 #Got: 5 apply_async(add, ('hello', 'world'), callback=r.handler) #再次调用 #Got: helloworld
第二种方法,使用闭包捕获外部信息
def make_handler(): sequence = 0 def handler(result): nonlocal sequence sequence += 1 print('[{}] Got: {}'.format(sequence, result)) return handler handler = make_handler() 调用函数 apply_async(add, (2, 3), callback=handler) #Got: 5 apply_async(add, ('hello', 'world'), callback=handler) #Got: helloworld
至少有两种方式来捕获和保存状态信息,可以在对象实例(通过绑定方法)或是一个闭包中保存
若使用闭包,需要注意可修改变量的操作,nonlocal表明变量在回调函数中修改
访问闭包中定义的变量
一般来讲,函数的闭包的变量不可被访问,但可以编写访问函数,并将其作为函数的属性绑定到闭包上来实现变量的访问
def sample(): n = 0 # Closure function def func(): print('n=', n) # Accessor methods for n,访问n变量 def get_n(): return n def set_n(value): nonlocal n n = value # Attach as function attributes 作为函数属性 func.get_n = get_n #将sample的调用对象作为调用者,将get_n函数作为属性 func.set_n = set_n #将set_n函数作为属性 return func f = sample() #调用函数 f() #调用内部函数 #n= 0 f.set_n(10) #设置变量n的值 f() #调用内部函数 #n= 10 f.get_n() #获取内部变量的值 #10
好啦,这就是关于python中函数的几点进阶技巧了,希望对大家有所帮助!