在 python 程序中创建、改变、查找变量名时,都是在一个保存变量名的空间中进行,我们称之为命名空间,也被称之为作用域。
python 的作用域是静态的,在源代码中变量名被赋值的位置决定了该变量能被访问的范围。即 python 变量的作用域由变量所在源代码中的位置决定
一般常用的开发语言在使用变量时(不同语言之间也会存在一些区别),大多分为以下四个过程:
1.变量声明:让编辑器知道有这么一个变量的存在
2.定义变量:为不同数据类型的变量分配内存空间
3.变量初始化:赋值,填充分配好的内存空间
4.引用变量:通过引用对象(变量名)来调用内存对象(内存数据)
在 python 中,使用一个变量时并不一定要求需要预先声明它,但是在真正使用它之前,它必须被绑定在某个内存对象(被定义、赋值);这种变量名的绑定将在当前作用域中引入新的变量,同时屏蔽外层作用域中的同名变量
在 python 中并不是所有的语句块中都会产生作用域。只有当变量在 module、class、def 中定义的时候,才会有作用域的概念
def func():
var = 100 # 局部作用域
print(var)
func() # 100
print(var) # NameError:name ‘var’ is not defined
在作用域中定义的变量,一般只在作用域中有效。需要注意的是:在 if - elif - else、for - else 、while、try-except-finally 等关键字语句块中并不会产生作用域
搜索变量名的优先级:局部作用域(local)>嵌套作用域(enclosing)>全局作用域(global)>内置作用域(built-in)
当在函数中使用未确定的变量名时,python 会按照优先级依次搜索 4 个作用域,以此来确定该变量名的意义。首先搜索局部作用域(L),之后是上一层嵌套结构中 def 或 lambda 函数的嵌套作用域(E),之后是全局作用域(G),最后是内置作用域(B)。按这个查找原则,在第一处找到的地方停止,如果都没有找到,抛出 NameError 错误
import builtins
dir(builtins)
输出:
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
# python是允许创建嵌套函数的,也就是说我们可以在函数内部定义一个函数,这些函数都遵循各自的作用域和生命周期
var = 100 # 全局作用域
def func():
var = 200 # 嵌套作用域
print(var)
def func2():
var = 300 # 局部作用域
print(var)
补充:python 解释器的运行过程:首先加载内存,再进行语法分析,之后再到编译,最后执行的过程
必须强调的是,内层作用域对外层作用域的变量只有只读(read-only)的访问权限,需要从内存到外层作用域的变量进行修改必须使用特殊关键字
# 在局部作用域中修改全局作用域的变量
x = 100
def func():
global x
x += 1
print(x)
func() # 101
print(x) # 101
nonlocal 关键字可以修改嵌套作用域的变量,nonlocal 关键字变量必须要在一个嵌套的 def 作用域中赋值过
# 在局部作用域中修改嵌套作用域的变量
def outer():
count = 10 # 嵌套作用域
def inner():
nonlocal count
count = 20 # 局部作用域
print(count)
inner()
print(count)
outer() # 20 , 20
简介:闭包函数返回的函数对象,不仅仅是一个函数对象,而是在该函数外包裹了一层作用域,使得该函数无论在何处被调用,都可以使用自己外层包裹的作用域
作用:函数封装,代码复用
装饰器函数:
就是用于扩展原函数功能的一种函数,目的是在不改变原函数功能的前提下,给函数增加新的功能
import time
from functools import wraps
def decorate(func):
@wraps(func)
def demo():
start = time.time()
func()
end = time.time()
print("消耗时长是%d" %(end - start))
return demo
@decorate
def foo():
time.sleep(3)
print("running")
return 'demo'
foo()