展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > Python的命名空间、作用域和装饰器的使用方法详解

Python的命名空间、作用域和装饰器的使用方法详解

一、名称空间和作用域1、命名空间(Namespace)命名空间是从名称到对象的映射,大部分的命名空间都是通过Python字典来实现的。命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。1、一般有三种命名空间:内置名称空间(built-innames):存放内置的名字,如len/eval/enumerate/bytes/max/min/sorted/map/filter....全局名称空间(global

本文目录

      一、名称空间和作用域

      1、命名空间(Namespace)

      命名空间是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。

      命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。

      1、一般有三种命名空间:
      • 内置名称空间(built-in names):存放内置的名字,如len/eval/enumerate/bytes/max/min/sorted/map/filter....

      • 全局名称空间(global names):模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。

      • 局部名称空间(local names):函数内部的名字都是局部名称空间,不同函数内部的名字互不干涉。

      Python的命名空间、作用域和装饰器的使用方法详解

      2、命名空间查找顺序:

      如果找不到变量 runoob,它将放弃查找并引发一个 NameError 异常:

      NameError: name 'runoob' is not defined。
      • 查找顺序:假设我们要使用变量 runoob,则 Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间。

      • 执行顺序:先内置(Python解释器启动的时候才会生成)-> 全局(文件执行的时候才会生成)-> 局部(函数调用的时候才会生成)

      3、命名空间的生命周期:

      命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。

      因此,我们无法从外部命名空间访问内部命名空间的对象。

      如下图所示,相同的对象名称可以存在于多个命名空间中。

      Python的命名空间、作用域和装饰器的使用方法详解

      2、作用域:

      作用域就是一个 Python 程序可以直接访问命名空间的正文区域。

      全局名称空间和局部名称空间中可能会存在名字相同的变量,但是这两个变量互不影响。

      Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。

      变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。

      Python的作用域一共有4种,分别是:

      • L(Local):最内层,包含局部变量,比如一个函数/方法内部。

      • E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。

      • G(Global):当前脚本的最外层,比如当前模块的全局变量。

      • B(Built-in): 包含了内建的变量/关键字等。,最后被搜索

      对于变量作用域,变量的访问以: L –> E –> G –>B 的 规则查找。

      在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。

      Python的命名空间、作用域和装饰器的使用方法详解

      举例:

      x = 1
      
      def func():
          print(x)  #10
      
      x = 10
      func()

      内置作用域是通过一个名为 builtin 的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能够使用它。

      在Python3.0中,可以使用以下的代码来查看到底预定义了哪些变量:

      import builtins
      print(dir(builtins))

      Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,

      如下代码:实例中 msg 变量定义在 if 语句块中,但外部还是可以访问的。如果将 msg 定义在函数中,则它就是局部变量,外部不能访问。

      if True:
          msg = 'I am from Runoob'
      print(msg)
      # 'I am from Runoob'

      3、全局变量和局部变量

      定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

      局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

      # 作用域注意点
      x = 1
      
      def f1():  # 定义阶段x=1
          print(x)  #1
      
      def f2():
          x = 2  #此x为f2函数的局部变量,f1无法直接访问
          f1()
      
      f2()

      4、函数对象+作用域应用

      def f1():
          def inner():
              print('from inner')
          return inner
      
      f = f1()  # from inner   。把局部定义的函数inner()放在全局之中
      
      def bar():
          f()
      
      bar()

      5、global关键字修改全局作用域中的变量

      函数内可以访问全局变量,但不能直接更新(修改)其值,可以加上 global 引用以更新变量值 :

      x = 1
      
      def f1():
          x = 2
      
          def f2():
              global x  # 修改全局
              x = 3
      
          f2()
      
      f1()
      print(x)  # 3

      6、nonlocal关键字修改嵌套作用域中的变量。

      如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了

      x = 1
      
      def f1():
          x = 2
      
          def f2():
              nonlocal x
              x = 3
      
          f2()
          print(x)  # 3
      
      f1()

      二、闭包函数

      闭包:闭是封闭(函数内部函数),包是包含(该内部函数对外部作用域而非全局作用域的变量的引用)。

      闭包指的是:函数内部函数对外部作用域而非全局作用域的引用。

      def outter(x):
          x = 1
      
          def inner():
              print(x)
      
          return inner #返回的是函数名(函数对象)
      
      
      f = outter(2)
      
      f()  # 1
      f()  # 1
      f()  # 1
      # 查看闭包的元素
      print(f.__closure__[0].cell_contents)  # 1

      闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。

      应用领域:

      延迟计算(原来我们是传参,现在我们是包起来)、爬虫领域。

      import requests
      
      
      def outter(url):
          def get():
              response = requests.get(url)
              print(f"done: {url}")
      
          return get
      
      
      baidu = outter('https://www.baidu.com')
      python = outter('https://www.python.org')
      
      baidu()
      baidu()
      
      python()
      python()

      三、函数装饰器

      装饰器指的是为被装饰器对象添加额外功能。因此定义装饰器就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能。装饰器的实现必须遵循两大原则:

      • 不修改被装饰对象的源代码

      • 不修改被装饰对象的调用方式

      装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。

      不改变函数体代码,并且不改变函数调用方式,它本质就是一个闭包函数。

      def f1(x):
          def f2():
              print(x)  # 10
          return f2
      
      f2 = f1()
      f2()  # f2()

      在不改变当前函数的情况下, 给其增加新的功能:

      def log(pr):  # 将被装饰函数传入
          def wrapper():
              print("**********")
              return pr()  # 执行被装饰的函数
      
          return wrapper  # 将装饰完之后的函数返回(返回的是函数名)
      
      
      @log
      def pr():
          print("我是小小洋")
      
      
      pr()
      
      # **********
      # 我是小小洋

      回调函数和返回函数的实例就是装饰器。

      四、无参装饰器

      举例:

      import time
      
      
      def index():
          print('welcome to index')
          time.sleep(1)
      
      
      def time_count(func):
          # func = 最原始的index
          def wrapper():
              start = time.time()
              func()
              end = time.time()
              print(f"{func} time is {start - end}")  #  time is -1.0038220882415771
      
          return wrapper
      
      
      index = time_count(index)  # index为被装饰函数index的内存地址,即index = wrapper
      index()  # wrapper()

      1、被装饰函数有返回值:

      如果原始的被装饰函数index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和wrapper()方法的返回值。

      import time
      
      
      def index():
          print('welcome to index')
          time.sleep(1)
          return 123
      
      
      def time_count(func):
          # func = 最原始的index
          def wrapper():
              start = time.time()
              res1 = func()
              end = time.time()
              print(f"{func} time is {start - end}")  #  time is -1.0050289630889893
              return res1
      
          return wrapper
      
      
      index = time_count(index)
      res = index()
      print(f"res: {res}")  #
      res: 123

      2、被装饰函数需要传参:

      如果原始的被装饰函数index()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有wrapper()=index(),所以给wrapper()方法传参即可。

      import time
      
      
      def index():
          print('welcome to index')
          time.sleep(1)
          return 123
      
      
      def home(name):
          print(f"welcome {name} to home page")
          time.sleep(1)
          return name
      
      
      def time_count(func):
          def wrapper(*args, **kwargs):
              start = time.time()
              res = func(*args, **kwargs)
              end = time.time()
              print(f"{func} time is {start-end}") #  time is -1.0039079189300537
              return res
      
          return wrapper
      
      
      home = time_count(home)
      
      res = home('egon')
      print(f"res: {res}") #res: egon

      3、装饰器模板

      def deco(func):
          def wrapper(*args,**kwargs):
              res = func(*args,**kwargs)
              return res
          return wrapper

      4、装饰器语法糖:

      在被装饰函数正上方,并且是单独一行写上@装饰器名

      import time
      
      
      def time_count(func): #装饰器
          # func = 最原始的index
          def wrapper(*args, **kwargs):
              start = time.time()
              res = func(*args, **kwargs)
              end = time.time()
              print(f"{func} time is {start-end}") # time is -1.0005171298980713
              return res
      
          return wrapper
      
      
      @time_count  # home = time_count(home)
      def home(name):
          print(f"welcome {name} to home page") #welcome egon to home page
          time.sleep(1)
          return name
      
      
      res = home('egon')
      print(f"res: {res}") #res: egon

      五、带参数的装饰器

      注意无参装饰器只套两层。

      import time
      
      current_user = {'username': None}
      
      
      def login(func):
          # func = 最原始的index
          def wrapper(*args, **kwargs):
              if current_user['username']:
                  res1 = func(*args, **kwargs)
                  return res1
      
              user = input('username: ').strip()
              pwd = input('password: ').strip()
      
              if user == 'nick' and pwd == '123':
                  print('login successful')
                  current_user['username'] = user
                  res1 = func(*args, **kwargs)
                  return res1
              else:
                  print('user or password error')
      
          return wrapper
      
      
      @login
      def index():
          print('welcome to index')
          time.sleep(1)
      
      
      res = index()
      
      #username: nick 
      #password: 123 
      #login successful 
      #welcome to index

      我们首先看看三层闭包怎么运用。

      def f1(y):
          def f2():
              x = 1
      
              def f3():
                  print(f"x: {x}")  # x: 1
                  print(f"y: {y}")  # x: 1
      
              return f3
          return f2
      
      
      f2 = f1(2)
      f3 = f2()
      f3()

      3、有参三层装饰器:

      在函数中嵌入装饰器

      import time
      
      current_user = {'username': None}
      
      
      def auth(engine='file'):
          def login(func):
              def wrapper(*args, **kwargs):
                  if current_user['username']:
                      res = func(*args, **kwargs)
                      return res
      
                  user = input('username: ').strip()
                  pwd = input('password: ').strip()
      
                  if engine == 'file':
                      print('base of file')
                      if user == 'nick' and pwd == '123':
                          print('login successful')
                          current_user['username'] = user
                          res = func(*args, **kwargs)
                          return res
                      else:
                          print('user or password error')
                  elif engine == 'mysql':
                      print('base of mysql, please base of file')
              return wrapper
          return login
      
      
      @auth(engine='file')
      def index():
          print('welcome to index')
          time.sleep(1)
      
      
      res = index()

      username: nick 
      password: 123 
      base of file 
      login successful 
      welcome to index

      六、类装饰器

      没错,装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

      class Foo(object):
          def __init__(self, func):
              self._func = func
      
          def __call__(self):
              print ('class decorator runing')
              self._func()
              print ('class decorator ending')
      
      @Foo
      def bar():
          print ('bar')
      
      bar()
      
      functools.wraps

      使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、__name__、参数列表,先看例子:

      # 装饰器
      def logged(func):
          def with_logging(*args, **kwargs):
              print func.__name__      # 输出 'with_logging'
              print func.__doc__       # 输出 None
              return func(*args, **kwargs)
          return with_logging
      
      # 函数
      @logged
      def f(x):
         """does some math"""
         return x + x * x
      
      logged(f)

      不难发现,函数 f 被with_logging取代了,当然它的docstring,__name__就是变成了with_logging函数的信息了。好在我们有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器里面的 func 函数中,这使得装饰器里面的 func 函数也有和原函数 foo 一样的元信息了。

      from functools import wraps
      
      def logged(func):
          @wraps(func)
          def with_logging(*args, **kwargs):
              print func.__name__      # 输出 'f'
              print func.__doc__       # 输出 'does some math'
              return func(*args, **kwargs)
          return with_logging
      
      @logged
      def f(x):
         """does some math"""
         return x + x * x

      七、装饰器顺序

      一个函数还可以同时定义多个装饰器,比如:

      @a
      @b
      @c
      def f ():
          pass

      它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于

      f = a(b(c(f)))

      八、装饰器使用场景

      现在我们来看一下装饰器在哪些地方特别耀眼,以及使用它可以让一些事情管理起来变得更简单。

      授权(Authorization)

      装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint)。它们被大量使用于Flask和Django web框架中。这里是一个例子来使用基于装饰器的授权:

      from functools import wraps
       
      def requires_auth(f):
          @wraps(f)
          def decorated(*args, **kwargs):
              auth = request.authorization
              if not auth or not check_auth(auth.username, auth.password):
                  authenticate()
              return f(*args, **kwargs)
          return decorated

      日志(Logging)

      日志是装饰器运用的另一个亮点。这是个例子:

      from functools import wraps
       
      def logit(func):
          @wraps(func)
          def with_logging(*args, **kwargs):
              print(func.__name__ + " was called")
              return func(*args, **kwargs)
          return with_logging
       
      @logit
      def addition_func(x):
         """Do some math."""
         return x + x
       
       
      result = addition_func(4)
      # Output: addition_func was called
      本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
      作者最新文章
      编程开发 Python
      相关文章 更多
      精品专题 更多
      装机必备

      正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

      Windows

      正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

      PDF教程

      正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

      macOS软件

      正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

      IOS软件

      正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

      AI

      正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

      Mac软件 更多
      Aperty macOS版
      Aperty macOS版

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      火山引擎 网页版
      火山引擎 网页版

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      立刻MV 网页版
      立刻MV 网页版

      立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

      蛙蛙写作 网页版
      蛙蛙写作 网页版

      蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

      讯飞智作 网页版
      讯飞智作 网页版

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      超级简历WonderCV 网页版
      超级简历WonderCV 网页版

      超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

      音述AI 网页版
      音述AI 网页版

      音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

      AionClaw macOS版
      AionClaw macOS版

      AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

      Loomy macOS版
      Loomy macOS版

      Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

      AirBuddy 3 macOS版
      AirBuddy 3 macOS版

      AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

      AirServer macOS版
      AirServer macOS版

      AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

      AnyDesk macOS版
      AnyDesk macOS版

      AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

      WINDOWS 更多
      讯飞绘文 网页版
      讯飞绘文 网页版

      讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

      Maya(Autodesk Maya) Windows版
      Maya(Autodesk Maya) Windows版

      Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

      Aperty Windows版
      Aperty Windows版

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      火山引擎 网页版
      火山引擎 网页版

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      立刻MV 网页版
      立刻MV 网页版

      立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

      蛙蛙写作 网页版
      蛙蛙写作 网页版

      蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

      讯飞智作 网页版
      讯飞智作 网页版

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      超级简历WonderCV 网页版
      超级简历WonderCV 网页版

      超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

      音述AI 网页版
      音述AI 网页版

      音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

      AionClaw Windows版
      AionClaw Windows版

      AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

      Loomy Windows版
      Loomy Windows版

      Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

      AirServer Windows版
      AirServer Windows版

      AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。