python函数高阶技巧与模式

下面是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中函数的几点进阶技巧了,希望对大家有所帮助!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯吶psycho

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值