Summary of Python advanced usage

  • 2020-09-16 07:36:55
  • OfStack

List derivation (list comprehensions)

Scenario 1: Combine all the elements in a 3d list with a in one dimension to form a new 2d list.

The simplest method: create a new list, iterate over the original 3-dimensional list, determine whether the 1-dimensional data is a, and if it is a, add the element append to the new list.
Cons: The code is too cumbersome, and for Python, execution will be much slower.

For scenario 1, we should first think of a list parsing solution, which can be solved in 1 line of code:


lista = [item for item in array if item[0] == 'a']

So, what is a list parse?

Official explanation: List parsing is a very simple but powerful generator built into Python that can be used to create list.

How does power manifest itself?

As you can see, the list parsing is shorter, but because it is a built-in use of Python, the underlying implementation is in the C language, which is faster than writing Python code.

Scenario 2: For a list, you iterate over both the index and the elements.

Here you can use the Python built-in function enumerate to get better indexes in the loop.


array = ['I', 'love', 'Python']
for i, element in enumerate(array):
  array[i] = '%d: %s' % (i, seq[i])

It can be reconstructed using the list derivation:


def getitem(index, element):
  return '%d: %s' % (index, element)

array = ['I', 'love', 'Python']
arrayIndex = [getitem(index, element) for index, element in enumerate(array)]

This is said to be written more like Pythonic.

Summary: If you want to do something with an existing iteratable object and then generate a new list, using list derivation is the easiest way.

Iterators and generators

Iterator (Iterator)

The iteration here can refer to the for loop. In Python, for loops can be used for things like list, dict, and files, but they are not iterators, they are iteratable objects.

What iterable objects

Simplest explanation: You can use for... in... The object that the statement loops through is the iteratable object (Iterable), which can be determined using the isinstance() method.


from collections import Iterable 
type = isinstance('python', Iterable)
print type

What is an iterator
An iterator is an object that can be called back and forth using the next() method, which can be used on an iteratable object to convert it to an iterator.


temp = iter([1, 2, 3])
print type(temp)
print next(temp)

So temp is an iterator. So iterators are based on two methods:

next: Return the next item iter returns the iterator itself

An object that can be understood to be called by the next() function and constantly return the next value is an iterator, and both methods will need to be defined when defining a decorator.

The advantages of iterators

When building an iterator, instead of loading all the elements once, the elements are returned when the next method is called, so there is no memory concern.

Iterator application scenarios

So, in what specific scenarios can iterators be used?

The scale of the data is enormous The sequence is regular, but cannot be described using a list derivation.

The generator

A generator is a high-level iterator that makes the code needed to return functions with 1 series of elements much simpler and more efficient (rather than the tedious task of creating iterator code).

Generator function

The generator function, based on the yield instruction, can pause 1 function and return an intermediate result. You can use a generator when you need a function that will return a sequence or execute in a loop, because when these elements are passed to another function for subsequent processing, returning one element at a time can effectively improve overall performance.
A common application scenario is to use the stream data buffer of the generator.

Generator expression

A generative expression is a convenient way to implement a generator by replacing the brackets of a list derivation with parentheses.
Difference from list derivation: List generation can directly create a table, but generator expression is a kind of loop calculation, so that the elements of the list can be deduced in the loop, one by one, without the need to create a complete list, thus saving a lot of space.


g = (x * x for x in range(10))

Summary: A generator is a high-level iterator. The advantage of generator is delayed calculation, which returns one result at a time, which is very suitable for the calculation of large data volume. However, one important thing to note with generators is that generators can only be traversed once.

lambda expression (anonymous function)

lambda expression is designed purely for the purpose of writing simple functions. It ACTS as a function sketch, making simple functions more concise.

The difference between lambda and def

lambda expressions can save the process of defining functions and make the code more concise and suitable for simple functions. def definitions are needed to write functions that deal with larger businesses.
The lambda expression is often used with the map(), reduce(), filter() functions

map(): The map function takes two arguments, one for a function and one for a sequence, where the function can take one or more arguments. map applies the passed function in turn to each element in the sequence, returning the result as a new list.
# Converts a number in a list to a string map(str, [1,2,3,4,5,6])

reduce () : The function takes two arguments, one a function and the other a sequence, but the function must take two arguments, reduce, to continue the result with the next element of the sequence for cumulative calculation. The result is reduce(f, [x1, x2, x3, x4]) = f(f(f(x (x1, x2), x3), x4).

filter() : This function is used for filtering, applying incoming functions to each element in turn, and then deciding whether to leave or discard the element depending on whether the function returns True or False.

A decorator

The decorator is essentially an Python function that allows other functions to add additional functionality without any code changes. With decorators, we can pull out a lot of the same code that has nothing to do with the function itself and continue to reuse it. Often used in scenarios with faceted requirements: insert logging, performance testing, transaction processing, caching, permission validation, and so on.

So why introduce decorators?

Scenario: Calculate the execution time of 1 function.

The first method is to define a function that is used to calculate the running time of the function. After the running time is calculated, the real business code will be processed. The code is as follows:


import time 

def get_time(func):
  startTime = time.time()
  func()
  endTime = time.time()
  processTime = (endTime - startTime) * 1000
  print "The function timing is %f ms" %processTime

def myfunc():
  print "start func"
  time.sleep(0.8)
  print "end func"

get_time(myfunc)
myfunc()

But the logic of this code breaks the logic that calls to all func functions need to be made using get_time(func).
So, is there a better way to show it? B: Of course. That's the decorator.

Write a simple decorator

With the above examples, write the decorator:


def get_time(func):
  def wrapper():
    startTime = time.time()
    func()
    endTime = time.time()
    processTime = (endTime - startTime) * 1000
    print "The function timing is %f ms" %processTime
  return wrapper
  
print "myfunc is:", myfunc.__name__
myfunc = get_time(myfunc)
print "myfunc is: ", myfunc.__name__
myfunc()

In this way, a simple, complete decorator is implemented, and you can see that the decorator does not affect the execution logic or the invocation of the function.
In Python, you can use the "@" syntax sugar to simplify the decorator code by changing the above example to:


@ get_time
def myfunc():
  print "start func"
  time.sleep(0.8)
  print "end func"

print "myfunc is: ", myfunc.__name__
myfunc()

** The order in which decorators are called **
Decorators can be used superimposed. If more than one decorator decorates a function at the same time, the decorator is called in the reverse order of the @ syntax sugar declaration, i.e. :


@decorator1
@decorator2
def func():
  pass

Equivalent to:

[

func = decorator1(decorator2(func()))

]

The decorated function takes arguments

In the above example, myfunc() has no arguments, so how would the decorator be written if parameters were added?


array = ['I', 'love', 'Python']
for i, element in enumerate(array):
  array[i] = '%d: %s' % (i, seq[i])
0

A decorator with parameters

Decorators have a lot of flexibility and support parameters themselves. For example, in the above example, @get_ES209en decorator only 1 parameter is a function that executes the business. Of course, parameters can also be added to the decorator for logical judgment.

Built-in decorator

Common class decorators in Python include @staticmathod, @ES216en, and @property

staticmethod: Static methods of a class, unlike member methods, have no self parameter and can be invoked without the class being instantiated. classmethod: The difference from the member method is that the first parameter received is not self but cls (the specific type of the current class) property: Represents information that can be accessed directly through an instance of the class.

Above is the advanced usage of Python, which will be updated continuously.


Related articles: