Show you about the python decorator

  • 2020-06-03 07:12:09
  • OfStack

1. Scope

In python, scope is divided into two types: global scope and local scope.

A global scope is a variable defined at the file level, the name of the function. The local scope, on the other hand, is defined inside the function.

There are two things I want to understand about scope: a. Variables defined locally cannot be accessed globally. Variables defined globally can be accessed locally, but variables defined globally cannot be modified (there are ways to modify).

Let's look at the following example:


x = 1
def funx():
  x = 10
  print(x) #  Print out the 10

funx()
print(x) #  Print out the 1

If the variable x is not locally defined, the function looks for x internally from the inside out, and if it is not found, an error is reported


x = 1
def funx():
  print(x) #  Print out the 1

funx()
print(x) #  Print out the 1

x = 1
def funx():
  def func1():
    print(x) #  Print out the 1
  func1()

funx()
print(x) #  Print out the 1

So, just remember two things about scope: global variables can be referenced anywhere in the file, but changes can only be made globally; If the local does not find the desired variable, it will look out and report an error if it does not.

2. High-level functions

We know that the name of the function refers to the address of one segment of memory space, so we can use this feature.

The a function name can be used as a value


def delete(ps):
  import os
  filename = ps[-1]
  delelemetns = ps[1]
  with open(filename, encoding='utf-8') as f_read,\
    open('tmp.txt', 'w', encoding='utf-8') as f_write:
    for line in iter(f_read.readline, ''):
      if line != '\n': #  Handle non-null lines 
        if delelemetns in line:
          line = line.replace(delelemetns,'')
        f_write.write(line)
  os.remove(filename)
  os.rename('tmp.txt',filename)

def add(ps):
  filename = ps[-1]
  addelemetns = ps[1]
  with open(filename, 'a', encoding='utf-8') as fp:
    fp.write("\n", addelemetns)

def modify(ps):
  import os
  filename = ps[-1]
  modify_elemetns = ps[1]
  with open(filename, encoding='utf-8') as f_read, \
      open('tmp.txt', 'w', encoding='utf-8') as f_write:
    for line in iter(f_read.readline, ''):
      if line != '\n': #  Handle non-null lines 
        if modify_elemetns in line:
          line = line.replace(modify_elemetns, '')
        f_write.write(line)
  os.remove(filename)
  os.rename('tmp.txt', filename)


def search(cmd):
  filename = cmd[-1]
  pattern = cmd[1]
  with open(filename, 'r', encoding="utf-8") as f:
    for line in f:
      if pattern in line:
        print(line, end="")
    else:
      print(" Could not find ")

dic_func ={'delete': delete, 'add': add, 'modify': modify, 'search': search}

while True:
  inp = input(" Please enter the action you want to take :").strip()
  if not inp:
    continue
  cmd_1 = inp.split()
  cmd = cmd_1[0]
  if cmd in dic_func:
    dic_func[cmd](cmd_1)
  else:
    print("Error")

b. The function name can be used as the return value


def outer():
  def inner():
    pass
  return inner

s = outer()
print(s)

###### The output result is #######
<function outer.<locals>.inner at 0x000000D22D8AB8C8>

c.. The function name can be taken as an argument


def index():
  print("index func")

def outer(index):
  s = index
  s()
  
outer(index)

###### The output #########

index func

So satisfying one of the above two conditions can be called a high-level function.

3. Closure functions

A closure function must satisfy two conditions :1. A function defined internally and 2. Contains a reference to an external scope rather than a global scope

Here are some examples to illustrate closure functions:

Example 1: The following only defines a function inside the function, but is not a closure function.


def outer():
  def inner():
    print("inner func excuted")
  inner() #  Calls to perform inner() function 
  print("outer func excuted")
outer() #  Calls to perform outer function 

#### The output result is ##########
inner func excuted
outer func excuted

Example 2: The following defines a function inside the function, and also refers to an external variable x, is this a closure function ? Answer: No


x = 1
def outer():
  def inner():
    print("x=%s" %x) #  Refer to the 1 A non inner Variables inside functions 
    print("inner func excuted")
  inner() #  perform inner function 
  print("outer func excuted")

outer()
##### The output ########
x=1
inner func excuted
outer func excuted

Let's go back to the definition of a closure function and see if both satisfy ? If you are smart, you will find that the variable x is a global variable, not a field variable. Consider the following example:


def outer():
  x = 1
  def inner():
    print("x=%s" %x)
    print("inner func excuted")
  inner()
  print("outer func excuted")

outer()

##### The output #########
x=1
inner func excuted
outer func excuted

Obviously, the above example satisfies the condition of the closure function. By now, it should be clear to you that as a closure function, you must satisfy both of the above conditions. However, in general, we return a value to a closure function. We won't say why here. You'll see the purpose of this return value in the next section.


def outer():
  x = 1
  def inner():
    print("x=%s" %x)
    print("inner func excuted")
  print("outer func excuted")
  return inner #  Returns the internal function name 
  
outer()

Now let's define closure functions in the abstract 1. It is an entity composed of a function and its associated reference environment. To implement a deep constraint, you need to create something that explicitly represents the reference environment and bind it to the associated subroutine, which is then bound as a closure. In the above example, we can see that a closure function must contain its own function and an external variable in order to truly be called a closure function. A function is not a closure function if it is not bound to an external variable.

So how do you know how many externally-referenced variables a closure function has? Take a look at the code below.


def outer():
  x = 1
  y = 2

  def inner():
    print("x= %s" %x)
    print("y= %s" %y)

  print(inner.__closure__)
  return inner

outer()

###### The output #######
(<cell at 0x000000DF9EA965B8: int object at 0x000000006FC2B440>, <cell at 0x000000DF9EA965E8: int object at 0x000000006FC2B460>)

The results show that within inner, two external local variables are referenced. If the reference is to a non-local variable, the output here is None.

Features of closure functions:

1. Built-in scope; 2. Delay calculation

So what do closure functions do? #63; We clearly know that when a closure function is defined, 1 must bind to an external environment. The whole thing counts as a closure function, so we can use this binding feature to accomplish some special functions.

Example 3: Download the page source according to the URL passed in


x = 1
def funx():
  print(x) #  Print out the 1

funx()
print(x) #  Print out the 1

x = 1
def funx():
  def func1():
    print(x) #  Print out the 1
  func1()

funx()
print(x) #  Print out the 1

0

One could say, well, that doesn't satisfy the condition of the closure function. I'm not referring to non-global external variables. That's not really the case. Here, we said before that any variable that is inside a function is a function. So I'm in index(url), and this url is also inside the function, except we're missing a step, so the above function is also a closure function.

4. A decorator

With the above foundation, the decorator is easy to understand.

Decorator: An external function passes in the name of the decorated function, and an internal function returns the name of the decorated function.

Features: 1. Do not modify the call method of the decorated function 2. Do not modify the source code of the decorated function

a. No reference decorators

In the following example, we need to calculate the execution time of the code under 1.


x = 1
def funx():
  print(x) #  Print out the 1

funx()
print(x) #  Print out the 1

x = 1
def funx():
  def func1():
    print(x) #  Print out the 1
  func1()

funx()
print(x) #  Print out the 1

1

Depending on the nature of the decorator, we cannot make any changes to index(), nor can we change the invocation style. At this point, we can use the decorator to complete the above functions.


x = 1
def funx():
  print(x) #  Print out the 1

funx()
print(x) #  Print out the 1

x = 1
def funx():
  def func1():
    print(x) #  Print out the 1
  func1()

funx()
print(x) #  Print out the 1

2

However, in some cases, decorated functions need to pass in parameters, and some functions do not need parameters, so how to deal with such variable parameter functions? Let's look at the use of parameter decorators.

b. Reference decorator


def outer(func): #  will index Is passed to func
  def inner(*args, **kwargs):
    start_time = time.time()
    func(*args, **kwargs)  # fun = index  namely func Save the outside index Function address 
    end_time = time.time()
    print(" Running time is %s"%(end_time - start_time))
  return inner #  return inner The address of the 

Here are some other examples.

If the decorated function has a return value


x = 1
def funx():
  print(x) #  Print out the 1

funx()
print(x) #  Print out the 1

x = 1
def funx():
  def func1():
    print(x) #  Print out the 1
  func1()

funx()
print(x) #  Print out the 1

4

Add 1 point, add that we want to execute the decorated function, then should be called as follows:

home = timmer(home) # returns the memory address of wrapper to the right of the equation and assigns it to home, where home is not the original function but the decorated one. Like home = timmer(home),python gives us a handy way to write @timmer before the decorated function. It works the same way as home = timmer(home).

If a function is decorated with multiple decorators, what is the order of execution.


x = 1
def funx():
  print(x) #  Print out the 1

funx()
print(x) #  Print out the 1

x = 1
def funx():
  def func1():
    print(x) #  Print out the 1
  func1()

funx()
print(x) #  Print out the 1

5

The experimental results show that a function is decorated by multiple decorators and its execution order is from bottom to top.

About decorators, there are 1 more advanced usage, interested in their own research.


Related articles: