资讯专栏INFORMATION COLUMN

python中关于闭包用法详解

89542767 / 361人阅读

  小编写这篇文章的主要目的,主要是来给大家介绍,关于python中,相关语法问题的解答,比如在python,我们会遇到闭包和装饰器不会用的情况,那么,下文就会来给大家做一个详细的解答。


  *args与**kwarsg及闭包和装饰器


  过程


  先理解闭包,再理解装饰器,不要忘了不定长参数


 deffunc():
  msg='111'
  deffunc1():
  print(msg)
  returnfunc1
  """


  1-理解闭包
  闭包即内部函数调用外部函数作用域里面的变量
  比如func1就是一个闭包函数
  """
  func()()#这里实际上是func1()
  """
  2-装饰器
  fn是被装饰的目标函数
  2.1-仅仅只是传递函数名的装饰器[基本不会用到]
  2.2-装饰带有参数的函数
  2.3-装饰带有返回值的函数
  2.4-装饰参数不确定的函数[可归类到装饰带有参数的函数里面]
  2.5-装饰器本身携带参数
  """


  defdecorator(fn):
  defwrapper():
  print("添加的功能,装饰不带有参数的函数")
  returnfn()
  returnwrapper
  @decorator
  deftest():
  print("原有功能")
  test()#实际上是decorator(test)
  defdecorator1(fn):
  defwrapper(n1,n2):
  print("添加的功能,装饰带有参数的函数")
  returnfn(n1,n2)
  returnwrapper
  @decorator1
  deftest1(a,b):
  print("a+b=%s"%(a+b))
  print("原有功能")
  test1(1,2)#实际上是decorator1(test1(1,2))
  defdecoretor2(fn):
  defwrapper():
  print("添加的功能,装饰带有返回值的函数")
  res=fn()
  returnres
  returnwrapper
  @decoretor2
  deftest2():
  print("原有功能")
  return"返回值001"
  a=test2()#实际是decorator2(test2)
  print(a)
  defdecorator3(fn):
  defwarpper(*args,**kwargs):
  print("添加的功能,装饰不定长参数的函数")
  returnfn(*args,**kwargs)
  returnwarpper
  @decorator3
  deftest3(n1,n2,n3):
  print("原有功能")
  print(n1+n2+n3)
  test3(1,2,3)#实际上是decorator1(test1(1,2,3))
  defdecorator4(home):
  deffunc_1(fn):
  defwrapper(*args,**kwargs):
  print("装饰器本身携带参数")
  print("目前家在%s"%(home))
  returnfn(*args,**kwargs)
  returnwrapper
  returnfunc_1
  @decorator4(home='wuhan')
  deftest4(n1,n2,n3):
  print("原有功能")
  print(n1+n2+n3)
  #test3(1,2,3)=decorator3(home="武汉")(test(1,2,3))()
  """

0.png

  1-先调用decorator3(home="wuhan")


  2-执行func_1(test(1,2,3))#到这里其实就和前面的装饰器一样


  3-执行wrapper


  4-执行test(1,2,3)


  """


  test4(1,2,3)


  Pythonfun(*args,**kwargs)中*args,**kwargs参数含义及用法


  1.Python函数中的两种参数


  我们知道,在Python中有两种参数


  位置参数(positionalargument):位置参数只能由参数位置决定


  关键词参数(keywordargument):关键词参数只需要用keyword=somekey的方法即可传参


  位置参数只能由参数位置决定。这也就决定了位置参数一定要在前面,否则关键词参数数量的变化都会使得位置无法判断。


  2.理解函数调用中的*


  *的作用是将tuple或者list中的元素进行unpack,分开传入,作为多个参数。


 deffunc(a,b,c)
     print(a,b,c)
  alist=[1,2,3]#这里alist的长度必须和函数中参数的个数相同,否则会报错
  func(*alist)   #等同于func(1,2,3)
  123


  2.1*做了什么


  它拆开数列alist的数值作为位置参数,并把这些位置参数传给函数func来调用。


  因此拆数列、传位置参数意味着func(*alist)与func(1,2,3)是等效的,因为alist=[1,2,3]。


  3.理解函数调用中的**


  **的作用是unpack字典,并将字典中的数据项作为键值参数传给函数。


  为了更好的理解举几个例子:


  deffunc(a,b,c):
    print(a,b,c)
     
  if__name__=="__main__":
    dic={'b':2,'c':3}
    func(1,b=2,c=3)
    func(1,**dic)
  123
  123


  4.理解函数调用中的*args和**kwargs


  kwargs是keywordargument的缩写,args就是argument。常见的是*args在**kwargs前面。


  这两个的用途和效果如下:


 defthis_fun(a,b,*args,**kwargs):
     """
     在这个函数定义中,参数”a,b”代表”常规参数列表”。
     args接收元组作为位置参数,而非是常见的参数列表
     
     """
    print(a,b)
    print(args)
    print(kwargs)
  if__name__='__main__'
     this_fun(0,1,2,3,index1=11,index2=22)
     
  0,1
  (2,3)
  {'index2':22,'index1':11}


  也就是说,第一中不定的参数形式把剩下的没有关键字的参数收起来形成一个tuple,而第二种把有关键字的收起来做成一个字典。


  5.实例说明args,kwargs的应用场景


  5.1子类传参给父类方法


  在任何时候继承类和重写方法的,我们应当用到args,kwargs将接收到的位置参数和键值参数给父类方法。通过实例我们更好的理解


  classModel(object):
    def__init__(self,name):
      self.name=name
    defsave(self,force_update=False,force_insert=False):
      ifforce_updateandforce_insert:
        raiseValueError("Cannotperformbothoperations")
      ifforce_update:
        print("Updatedanexistingrecord")
      ifforce_insert:
        print("Createdanewrecord")


  定义一个类,我们可以创建类的对象,类的对象有一个方法save().假设类的对象可以通过save()方法保存到数据库中。通过函数save()参数来决定是否在数据库中创建一条记录或者更新现存的记录。


  构造一个新类,类有Model的行为,但只有符合某些条件才会保存这个类的对象。这个新类继承Model,重写Model的save()


  classChildModel(Model):
    defsave(self,*args,**kwargs):
      ifself.name=='abcd':
        super(ChildModel,self).save(*args,**kwargs)
      else:
        returnNone


  实际上对应的保存动作发生在’Model’的save方法中。所以我们调用子类的的save()方法而非’Model’的方法.子类ChildModel的save()接收任何父类save()需要的参数,并传给父类方法。因此,子类save()方法参数列表中有*args和**kwargs,它们可以接收任意位置参数或键值参数,常规参数列表除外。


  下面创建ChildModel实体并调用save方法:


  c=ChildModel('abcd')
  c.save(force_insert=True)
  c.save(force_update=True)
  #结果
  Createdanewrecord
  Updatedanexistingrecord


  这里传参数给对象的save()方法。调用的是子类的save(),它接收一个包含关键字参数kwargs的字典。然后,它使用**将字典作为关键字参数unpack,然后将其传递给超类save()。因此,超类save()获得关键字参数force_insert并执行相应的操作。


  5.2*args实现sum


  defmy_sum(*args):
     res=0
     forvalinargs:
        res+=val
     returnres
     
  l1=[4,8]
  l2=[1,2,3]
  print(my_sum(*l1))      #12
  print(my_sum(*l2))      #6
  print(my_sum(4,5,6))   #15

综上所述,就为大家介绍到这里了,希望可以为大家带来帮助。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/127833.html

相关文章

  • JavaScript深入浅出

    摘要:理解的函数基础要搞好深入浅出原型使用原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。中文指南基本操作指南二继续熟悉的几对方法,包括,,。商业转载请联系作者获得授权,非商业转载请注明出处。 怎样使用 this 因为本人属于伪前端,因此文中只看懂了 8 成左右,希望能够给大家带来帮助....(据说是阿里的前端妹子写的) this 的值到底...

    blair 评论0 收藏0
  • 工具使用-积累与发现

    摘要:一积累中如何快速查看包中的源码最常用的大开发快捷键技巧将对象保存到文件中从文件中读取对象中的用法的配置详解和代码的格式详解格式化内容设置生成详解注释规范中设置内存调试的小知识单步执行命令的区别的动态代理机制详解内容有瑕疵,楼指正泛型继承的几 一、积累 1.JAVA Eclipse中如何快速查看jar包中 的class源码 最常用的15大Eclipse开发快捷键技巧 Java将对象保存到...

    wangjuntytl 评论0 收藏0
  • 工具使用-积累与发现

    摘要:一积累中如何快速查看包中的源码最常用的大开发快捷键技巧将对象保存到文件中从文件中读取对象中的用法的配置详解和代码的格式详解格式化内容设置生成详解注释规范中设置内存调试的小知识单步执行命令的区别的动态代理机制详解内容有瑕疵,楼指正泛型继承的几 一、积累 1.JAVA Eclipse中如何快速查看jar包中 的class源码 最常用的15大Eclipse开发快捷键技巧 Java将对象保存到...

    Lyux 评论0 收藏0
  • javascript中关作用域和闭包

    摘要:在代码执行时,对应的作用域链常常是保持静态的。当语句执行完毕后,会把作用域链恢复到原始状态。在全局作用域中创建的函数,其作用域链会自动成为全局作用域中的一员。 列表项目 前言 学习了javascript已经很久了,关于这个语言中的这两个特性也是早已耳熟能详,但是在实际的使用的过程中或者是遇到相关的问题的时候,还是不能很好的解决。因此我觉得很有必要深入的学习并且记录这个问题,以便在今后的...

    zacklee 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<