ネームスペースは、名前からまでです。オブジェクト マッピングの場合、ほとんどの名前空間は Python ディクショナリを通じて実装されます。
ネームスペースは、プロジェクト内での名前の競合を回避する方法を提供します。各名前空間は独立しており、関係がないため、1 つの名前空間に重複した名前が存在することはできませんが、異なる名前空間では影響なく重複した名前を持つことができます。
組み込み名前空間 (組み込み名): 組み込み名を格納します。 as len/eval/enumerate/bytes/max/min/sorted/map/filter....
(グローバル名) : モジュールで定義された名前には、関数、クラス、他のインポートされたモジュール、モジュール レベルの変数および定数を含むモジュールの変数が記録されます。
(ローカル名): 関数内の名前はすべてローカル名前空間であり、異なる関数内の名前は互いに干渉しません。
NameError: name 'runoob' is not defined。
Go to local namespace->Global namespace->Built -名前空間内。
グローバル名前空間とローカル名前空間に同じ名前の変数が存在する場合がありますが、これら 2 つの変数は相互に影響しません。
Python では、プログラム変数はどこからでもアクセスできるわけではなく、変数に値が割り当てられている場所によってアクセス許可が異なります。 変数のスコープによって、プログラムのどの部分がどの特定の変数名にアクセスできるかが決まります。 Python スコープには 4 つのタイプがあります。L (ローカル) : 最も内側の層。次のようなローカル変数が含まれます。関数/メソッドの内部。
E (囲み) : 非ローカル (非ローカル) および非グローバル (非グローバル) 変数が含まれます。たとえば、入れ子になった関数が 2 つあり、関数 (またはクラス) A に関数 B が含まれている場合、B の名前については、A のスコープは非ローカルになります。
G (グローバル) : 現在のモジュールのグローバル変数など、現在のスクリプトの最も外側の層。
B(組み込み): 組み込みの変数/キーワードなどが含まれます。 、そして最終的に検索されました
L –> E –> G –>B 。
ローカルで見つからない場合は、ローカル エリアの外側の部分 (クロージャなど) で検索し、見つからない場合はグローバルで検索してから、組み込みで検索されます。 例:x = 1 def func(): print(x) #10 x = 10 func()組み込みスコープは、builtin という名前の標準モジュールを通じて実装されますが、変数名自体は組み込みスコープには組み込まれません。スコープ内にあるため、このファイルを使用するにはこのファイルをインポートする必要があります。 Python3.0 では、次のコードを使用してどの変数が事前定義されているかを確認できます:
import builtins print(dir(builtins))モジュール、クラス、関数 (def、lambda) のみがあり、新しいスコープが導入されます。他のコード ブロック (if/elif/else/、try/excel、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()
def f1(): def inner(): print('from inner') return inner f = f1() # from inner 。把局部定义的函数inner()放在全局之中 def bar(): f() bar()
函数内可以访问全局变量,但不能直接更新(修改)其值,可以加上 global 引用以更新变量值 :
x = 1 def f1(): x = 2 def f2(): global x # 修改全局 x = 3 f2() f1() print(x) # 3
如果要修改嵌套作用域(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()
如果原始的被装饰函数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
如果原始的被装饰函数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
def deco(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res return wrapper
在被装饰函数正上方,并且是单独一行写上@装饰器名
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()
在函数中嵌入装饰器
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)))
现在我们来看一下装饰器在哪些地方特别耀眼,以及使用它可以让一些事情管理起来变得更简单。
装饰器能有助于检查某个人是否被授权去使用一个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
日志是装饰器运用的另一个亮点。这是个例子:
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
以上がPython の名前空間、スコープ、デコレータを使用するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。