Python 函数作用域、闭包、装饰器

发布于 2021-02-24 14:13:34 字数 4255 浏览 1067 评论 0

Python 中的函数作用域

  • L > E > G > B
  • L:local 函数内部作用域
  • E:enclosing 函数内部与内嵌函数之间
  • G:global 全局作用域
  • B:build-in 内置作用域

Python 中的闭包

闭包的作用:封装、代码复用

  #coding:UTF-8
  def fun_150(val):
      passline = 90
      if val > passline:
          print ('pass')
      else:
          print ('failed')
  def fun_100(val):
      passline = 60
      if val > passline:
          print ('pass')
      else:
          print ('failed')
  def set_passline(passline):
      def cmp(val):
          if val > passline:
              print ('pass')
          else:
              print ('failed')
      return cmp
  
  f_100 = set_passline(60)
  f_150 = set_passline(90)

根据上面的代码我们可以看出函数 cmp()其实就是一个闭包,闭包的优越性就是可是在外部引用不同的变量使得我们的代码具有高可复用性。通过上面的示例我们发现其实 f_100fun_100的效果是一致的。

闭包就是函数对我们作用域 enclosing 的一个使用,变量放到 clouser 属性中 ,这个时候我们可以拿过来直接使用,这就是闭包的一个基本使用情况。

上面是闭包的第一种使用情况,下面讲解闭包的第二种使用情况。

分别构建两个函数,一个求和函数my_sum()和一个求平均值函数 my_average()

#coding:UTF-8 def my_sum(*arg): return sum(*arg) def my_average(*arg): return sum(arg)/len(arg)

my_sum(1,2,3,4,5) 15 my_average(1,2,3,4,5) 3

但是但我们运行下面的方法就会出现错误:

my_sum(1,2,3,4,5,'6') my_average()

因为此时的分母为0了,求和中不能支持 int 类型和 str 类型的数值相加。所以我们就需要加上判断条件。但我们加上判断条件后发现代码是一样的,这样不符合我们的代码规范,并且代码就没有高可复用的特性了。

    #coding:UTF-8
    def my_sum(*arg):
        if len(arg) == 0
            return 0
        for val in arg:
            if not isinstance(val,int):
                return 0 
        return sum(*arg)
    def my_average(*arg):
        if len(arg) == 0
            return 0
        for val in arg:
            if not isinstance(val,int):
                return 0 
        return sum(arg)/len(arg)

我们想到 Python 的特性之一有一个就是高阶函数的使用,可以使用函数为变量。因此我们创建一个新的函数 dec(func)来保存相同的功能代码。

#coding:UTF-8
def dec(func):
def in_dec(*arg):
if len(arg) == 0
return 0
for val in arg:
if not isinstance(val,int):
return 0
return func(*arg) return in_dec

这样我们就可以直接调用函数来进行操作了。

    #coding:UTF-8
    def my_sum(*arg):
        return sum(*arg)
    def my_average(*arg):
        return sum(arg)/len(arg)
    def dec(func):
        def in_dec(*arg):
            if len(arg) == 0
                return 0
            for val in arg:
                if not isinstance(val,int):
                    return 0 
            return func(*arg)
        return in_dec
    
    >>>my_sum1 = dec(my_sum)
    >>>my_average1 = dec(my_average)
    
    >>>my_sum1(1,2,3,4,5)
    15
    >>>my_sum1(1,2,3,4,5,'6')
    0
    >>>my_average1(1,2,3,4,5)
    3
    >>>my_average1()
    0

这个时候代码执行的流程是先执行的 in_dec() 里面的内容然后再执行 func(*arg) 的内容,即函数真正需要做不同运行的部分,然后再返回值。

Python 中的装饰器

  1. 装饰器用来装饰函数;
  2. 返回一个函数对象;
  3. 被装饰函数标识符指向返回的函数对象;
  4. 语法糖 @deco

装饰器的实质就是对闭包的一种使用。

    #coding:UTF-8
    def dec(func):
        def in_dec(*arg):
            if len(arg) == 0
                return 0
            for val in arg:
                if not isinstance(val,int):
                    return 0 
            return func(*arg)
        return in_dec
        
    @dec
    def my_sum(*arg):#my_sum = in_dec
        return sum(*arg)
    def my_average(*arg):
        return sum(arg)/len(arg)
    
    
    >>>my_sum1 = dec(my_sum)
    >>>my_average1 = dec(my_average)
    
    >>>my_sum1(1,2,3,4,5)
    15
    >>>my_sum1(1,2,3,4,5,'6')
    0
    >>>my_average1(1,2,3,4,5)
    3
    >>>my_average1()
    0

但我们看到@的语法糖的时候要注意代码的执行过程,例如下面的代码中的执行过程是:

    def deco(func):
        def in_deco(x,y):
            print ('in deco')
            func(x,y)
        print ('deco')
        return in_deco
    @deco
    def bar(x,y):
        print ('in bar',x+y)

调用过程:

  1. @deco(bar) => in_deco
  2. bar => in_deco
  3. bar() = in_deco() = bar()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

linfzu01

文章 0 评论 0

可遇━不可求

文章 0 评论 0

枕梦

文章 0 评论 0

qq_3LFa8Q

文章 0 评论 0

JP

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文