Heim > Backend-Entwicklung > Python-Tutorial > Wie verwende ich Pythons Namespaces, Bereiche und Dekoratoren?

Wie verwende ich Pythons Namespaces, Bereiche und Dekoratoren?

PHPz
Freigeben: 2023-05-09 19:04:17
nach vorne
805 Leute haben es durchsucht

    1. Namespace und Geltungsbereich

    1. Namespace (Namespace)

    Namespace ist eine Zuordnung von Namen zu Objekten.

    Namespaces bieten eine Möglichkeit, Namenskonflikte in Projekten zu vermeiden. Jeder Namespace ist unabhängig und hat keine Beziehung, daher kann es in einem Namespace keine doppelten Namen geben, verschiedene Namespaces können jedoch ohne Auswirkungen doppelte Namen haben.

    1 Der Name zeichnet die Variablen des Moduls auf, einschließlich Funktionen, Klassen, anderen importierten Modulen, Variablen und Konstanten auf Modulebene.
    • Lokaler Namespace

      (lokale Namen): Die Namen innerhalb der Funktion sind alle lokale Namespaces, und die Namen innerhalb verschiedener Funktionen stören sich nicht gegenseitig. len/eval/enumerate/bytes/max/min/sorted/map/filter....

    • 2. Namespace-Suchreihenfolge:

      Wenn die Variable runoob nicht gefunden wird, wird die Suche abgebrochen und eine NameError-Ausnahme ausgelöst:
    • NameError: name 'runoob' is not defined。
      Nach dem Login kopieren
    • Suchreihenfolge: Angenommen, wir möchten die Variable verwenden runoob, dann Python Die Suchreihenfolge lautet: Gehe zum lokalen Namespace -> globaler Namespace -> integrierter Namespace

      .

    Wie verwende ich Pythons Namespaces, Bereiche und Dekoratoren?Ausführungsreihenfolge: Zuerst integriert (wird generiert, wenn der Python-Interpreter gestartet wird) -> Global (wird generiert, wenn die Datei ausgeführt wird) -> Lokal (wird generiert, wenn die Funktion aufgerufen wird)

    3. Namespace-Lebenszyklus:

      Der Lebenszyklus eines Namespace hängt vom Umfang des Objekts ab. Wenn die Objektausführung abgeschlossen ist, endet der Lebenszyklus des Namespace.
    • Daher können wir vom äußeren Namensraum aus nicht auf die Objekte des inneren Namensraums zugreifen. Wie in der folgenden Abbildung dargestellt, kann derselbe Objektname in mehreren Namespaces vorhanden sein.

    • 2. Scope:
    Scope ist der Körperbereich eines Namespace, auf den ein Python-Programm direkt zugreifen kann.

    Variablen mit demselben Namen können im globalen Namespace und im lokalen Namespace vorhanden sein, diese beiden Variablen beeinflussen sich jedoch nicht gegenseitig.

    In Python sind Programmvariablen nicht überall zugänglich. Zugriffsberechtigungen hängen davon ab, wo der Variablen ein Wert zugewiesen wird.

    Der Gültigkeitsbereich einer Variablen bestimmt, welcher Teil des Programms auf welchen spezifischen Variablennamen zugreifen kann.

    Wie verwende ich Pythons Namespaces, Bereiche und Dekoratoren?Python verfügt über 4 Arten von Bereichen:

    L (Lokal)

    : Die innerste Ebene, einschließlich lokaler Variablen, z. B. innerhalb einer Funktion/Methode.

    E (Einschließend)

    : Enthält nicht lokale und nicht globale Variablen. Wenn beispielsweise zwei verschachtelte Funktionen vorhanden sind und eine Funktion (oder Klasse) A eine Funktion B enthält, ist der Gültigkeitsbereich in A für den Namen in B nicht lokal.

    • G (Global)

      : Die äußerste Ebene des aktuellen Skripts, z. B. die globalen Variablen des aktuellen Moduls.

    • B (integriert)

      : Enthält integrierte Variablen/Schlüsselwörter usw. , und schließlich gesucht

    • Für den Variablenbereich wird der Variablenzugriff nach den Regeln von
    • L –> E –>B durchsucht.

      Wenn es lokal nicht gefunden werden kann, wird es lokal gesucht (z. B. bei Schließungen). Wenn es nicht gefunden werden kann, wird es global und dann in der integrierten Datenbank gesucht.

    • Beispiel:

      x = 1
      
      def func():
          print(x)  #10
      
      x = 10
      func()
      Nach dem Login kopieren

      Der integrierte Bereich wird durch ein Standardmodul namens „Builtin“ implementiert, aber der Variablenname selbst wird nicht im integrierten Bereich platziert, daher muss diese Datei importiert werden, um ihn zu verwenden.
    In Python3.0 können Sie den folgenden Code verwenden, um zu sehen, welche Variablen vordefiniert sind:

    import builtins
    print(dir(builtins))
    Nach dem Login kopieren
    In Python führen nur Module, Klassen und Funktionen (def, lambda) neue Domänenfunktionen ein, andere Codeblöcke (z. B. if /elif/else/, try/exclusive, for/while usw.) führt keine neuen Bereiche ein, was bedeutet, dass auf die in diesen Anweisungen definierten Variablen auch von außen zugegriffen werden kann,

    Der folgende Code: Im Beispiel, Die msg-Variable wird im if-Anweisungsblock definiert, ist aber dennoch von außen zugänglich. Wenn msg in einer Funktion definiert ist, handelt es sich um eine lokale Variable, auf die von außen nicht zugegriffen werden kann.

    if True:
        msg = 'I am from Runoob'
    print(msg)
    # 'I am from Runoob'
    Nach dem Login kopieren

    3. Globale Variablen und lokale Variablen

    Wie verwende ich Pythons Namespaces, Bereiche und Dekoratoren?Variablen, die innerhalb der Funktion definiert sind, haben einen lokalen Gültigkeitsbereich, und Variablen, die außerhalb der Funktion definiert sind, haben einen globalen Gültigkeitsbereich.

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

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

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

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

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

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

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

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

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

    x = 1
    
    def f1():
        x = 2
    
        def f2():
            nonlocal x
            x = 3
    
        f2()
        print(x)  # 3
    
    f1()
    Nach dem Login kopieren

    二、闭包函数

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

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

    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
    Nach dem Login kopieren

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

    应用领域:

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

    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()
    Nach dem Login kopieren

    三、函数装饰器

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

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

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

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

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

    def f1(x):
        def f2():
            print(x)  # 10
        return f2
    
    f2 = f1()
    f2()  # f2()
    Nach dem Login kopieren

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

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

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

    四、无参装饰器

    举例:

    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()
    Nach dem Login kopieren

    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
    Nach dem Login kopieren

    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
    Nach dem Login kopieren

    3、装饰器模板

    def deco(func):
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            return res
        return wrapper
    Nach dem Login kopieren

    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
    Nach dem Login kopieren

    五、带参数的装饰器

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

    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
    Nach dem Login kopieren

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

    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()
    Nach dem Login kopieren

    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()
    Nach dem Login kopieren

    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
    Nach dem Login kopieren

    使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的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)
    Nach dem Login kopieren

    不难发现,函数 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
    Nach dem Login kopieren

    七、装饰器顺序

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

    @a
    @b
    @c
    def f ():
        pass
    Nach dem Login kopieren

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

    f = a(b(c(f)))
    Nach dem Login kopieren

    八、装饰器使用场景

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

    授权(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
    Nach dem Login kopieren

    日志(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
    Nach dem Login kopieren

    Das obige ist der detaillierte Inhalt vonWie verwende ich Pythons Namespaces, Bereiche und Dekoratoren?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Verwandte Etiketten:
    Erklärung dieser Website
    Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
    Beliebte Tutorials
    Mehr>
    Neueste Downloads
    Mehr>
    Web-Effekte
    Quellcode der Website
    Website-Materialien
    Frontend-Vorlage