Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

The introduction of Python function and the introduction of decorator

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces "Python function introduction and decorator entry usage". In daily operation, I believe many people have doubts about the introduction of Python function and decorator entry usage. Xiaobian consulted all kinds of materials and sorted out simple and easy to use operation methods. I hope to answer your doubts about "Python function introduction and decorator entry usage"! Next, please follow the small series to learn together!

Python allows you, as a programmer, to do cool things with functions. In Python programming, functions are first-class objects, which means you can use them just like strings, integers, or any other object.

For example, you can assign functions to variables:

>>> def square(n):... return n * n;>>> square(4)16>>> alias = square>>> alias(4)16

However, the real power of first-class functions is that you can pass functions to other functions, or return functions from other functions. Python's built-in function map takes advantage of this ability: you pass map a function and a list, and it calls the function you pass it with arguments to each element of the list in turn, generating a new list. The following example applies the square function above:

>>> number = [1, 2, 3, 4, 5]>>> map(square, numbers)[1, 4, 9, 16, 25]

A function is called a higher order function if it accepts other functions as arguments and/or returns a function. Although the map function simply uses the function we passed it without changing it, we can also use higher-order functions to change the behavior of other functions.

For example, suppose there is a function that is called so many times that it is expensive to run:

>>> def fib(n):... "Recursively (i.e., dreadfully) calculate the nth Fibonacci number. "... return n if n in [0, 1] else fib(n - 2) + fib(n - 1)

We usually save the result of each recursive call in the calculation process, so that for a certain n that often appears in the function call tree, when we need to calculate the result corresponding to n, we do not need to repeat the calculation. There are many ways to do this. For example, we can store these results in a dictionary, and when we call fib with a value as an argument, we first check this dictionary to see if its result has been calculated.

But then, every time we want to call fib, we need to repeat the same dictionary check boilerplate code. Conversely, if fib is responsible for storing its results internally, it is convenient to call fib in other code by simply calling it. Such a technique is called memoization(note the absence of the letter r).

We could put this memoization code directly into fib functions, but Python gives us a more elegant alternative. Since it is possible to write functions that modify other functions, we can write a generic memoization function that takes a function as an argument and returns the memoization version of the function:

def memoize(fn): stored_results = {} def memoized(*args): try: # try to get the cached result return stored_results[args] except KeyError: # nothing was cached for those args. let's fix that. result = stored_results[args] = fn(*args) return result return memoized

As above, the memoize function takes another function as an argument, and a dictionary object is created in the function body to store the result of the function call: the key is the argument to the memoized wrapped function, and the value is the return value of the function call with the key as the argument. The memoize function returns a new function that first checks whether there is an entry in the stored_results dictionary corresponding to the current parameter; if there is, the corresponding stored value is returned; otherwise, the wrapped function is called, stores its return value, and returns it to the caller. This new function returned by memoize is often called a "wrapper" function because it is just a thin layer outside of another function that actually works.

Well, now that we have a memoization function, we can pass fib to it and get a wrapped fib, this version of fib doesn't have to repeat the heavy lifting of the previous one:

def fib(n): return n if n in [0, 1] else fib(n - 2) + fib(n - 1)fib = memoize(fib)

With the higher-order function memoize, we get the benefits of memoization without having to make any changes to fib itself, so as not to obscure the actual work of the function with the code of memoization. However, you may notice that the above code is a bit awkward because we have to write fib three times. Since this pattern-passing one function to another and then returning the result to a function variable with the same name as the original function-is extremely common in code that uses wrapper functions, Python provides a special syntax for it: decorators:

@memoizedef fib(n): return n if n in [0, 1] else fib(n - 2) + fib(n -1)

Here, we say that the memoize function decorates the fib function. It should be noted that this is only a grammatical shorthand. This code does the same thing as the previous snippet: define a function named fib, pass it to the memoize function, and store the return result in a function variable named fib. The special (odd-looking)@ syntax just reduces redundancy.

You can stack multiple decorators and they work from bottom to top. For example, suppose we have another higher-order function to help debug:

def make_verbose(fn): def verbose(*args): # will print (e.g.) fib(5) print '%s(%s)' % (fb.__ name__, ', '.join(repr(arg) for arg in args)) return fn(*args) # actually call the decorated function return verbose

The following two code snippets do the same thing:

@memoize@make_verbosedef fib(n): return n if n in [0, 1] else fib(n - 2) + fib(n - 1)def fib(n): return n if n in [0, 1] else fib(n - 2) + fib(n - 1)fib = memoize(make_verbose(fib))

Interestingly, Python doesn't restrict you to writing only one function name after the @ sign: you can also call a function and pass arguments efficiently to decorators. Suppose we are not satisfied with simple memoization, but want to store the result of the function in memcached. If you have written a memcached decorator function, you can (for example) pass it a server address:

@memcached('127.0.0.1:11211')def fib(n): return n if n in [0, 1] else fib(n - 2) + fib(n - 1)

The syntax for non-decorators expands as follows:

fib = memcached('127.0.0.1:11211')(fib)

Python comes with some very useful functions for use as decorators. For example, Python has a classmethod function that creates static methods roughly similar to java:

class Foo(object): SOME_CLASS_CONSTANT = 42 @classmethod def add_to_my_constant(cls, value): # Here, `cls` will just be Foo, buf if you called this method on a # subclass of Foo, `cls` would be that subclass instead. return cls.SOME_CLASS_CONSTANT + valueFoo.add_to_my_constant(10) # => 52# unlike in Java, you can also call a classmethod on an instancef = Foo()f.add_to_my_constant(10) # => 52

Side note: Document string

Python functions can contain more information than just code: they also contain helpful information, such as function names, documentation strings:

>>> def fib(n):... "Recursively (i.e., dreadfully) calculate the nth Fibonacci number. "... return n if n in [0, 1] else fib(n - 2) + fib(n - 1)...>>> fib.__ name__'fib'>>> fib.__ doc__'Recursively (i.e., dreadfully) calculate the nth Fibonacci number. '

This is what Python's built-in help function outputs. However, when the function is wrapped, we see the wrapper function name and docstring:

>>> fib = memoized(fib)>>> fib.__ name__'memoized'>>> fib.__ doc__

Information like that is useless. Fortunately, Python includes a helper function called functools.wraps that copies the help information for a function into its wrapper function:

import functoolsdef memoize(fn): stored_results = {} @functools.wraps(fn) def memoized(*args): # (as before) return memoized

Using decorators to help you write decorators will make a lot of things very satisfying. Now, if we retry the previous code using the updated memoize function, we'll see the document preserved:

>>> fib = memoized(fib)>>> fib.__ name__'fib'>>> fib.__ doc__'Recursively (i.e., dreadfully) calculate the nth Fibonacci number. 'At this point, the study of "Introduction to Python functions and introduction to decorators" is over, hoping to solve everyone's doubts. Theory and practice can better match to help everyone learn, go and try it! If you want to continue learning more relevant knowledge, please continue to pay attention to the website, Xiaobian will continue to strive to bring more practical articles for everyone!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report