Discuss Python advanced programming techniques and examples

Source: Internet
Author: User
Tags class definition constructor data structures generator wrapper zip in python

Before we talked about the Python advanced data Structure Learning tutorial, let's take a look at some of the advanced Python design structures and how they are used.


in daily work, you can choose the right data structure for your needs, such as requirements for fast lookup, requirements for data consistency, or requirements for indexing, and you can combine various data structures appropriately to generate logical and understandable data models. Python's data structure clause is intuitive and provides a wide range of optional operations. This guide attempts to put together most commonly used data structure knowledge and provides an exploration of its best usage.

inferred (comprehensions)

If you've been using Python for a long time, you should at least have heard of list derivation (listing comprehensions). This is a way to place a for loop, an if expression, and an assignment statement in a single statement. In other words, you can map or filter a list through an expression.

A list derivation contains the following sections:

    An input sequence
    A variable that represents the input sequence member
     An optional assertion expression
    an output expression that converts a member in an input sequence that satisfies an assertion expression to an output list member

for example, We need to generate a new sequence of all the squares of integers greater than 0 from an input list, and you might write this:

num = [1, 4, -5, ten,-7, 2, 3,-1]
filtered_and_squared = [] for number in
num:
if number > 0:
   filtered_and_squared.append (Number * * 2)
print filtered_and_squared
# [1, 16, 100, 4, 9]


It's simple, isn't it? But there are 4 lines of code, two layers of nesting plus a completely unnecessary append operation. And if you use the filter, lambda, and map functions, you can greatly simplify your code:

num = [1, 4,-5, 10,-7, 2, 3,-1]
filtered_and_squared = map (Lambda x:x * * 2, filter (lambda x:x > 0, num))
Print filtered_and_squared

# [1, 16, 100, 4, 9]

Well, this way the code will unfold horizontally. So is it possible to continue simplifying the code? List deduction can give us the answer:

num = [1, 4,-5, 10,-7, 2, 3,-1]
filtered_and_squared = [x**2 for x in num if x > 0]
Print filtered_and_squared

# [1, 16, 100, 4, 9]

The

    iterator (iterator) traverses each member X
    assertion of the input sequence num to determine whether each member is greater than 0
    If the member is greater than 0, it is sent to the output expression, after which the square becomes a member of the output list. The

List derivation is encapsulated in a list, so it is obvious that it can immediately generate a new list. There is only one type function call without an implicit invocation of the lambda function, and the list derivation uses a regular iterator, an expression, and an if expression to control optional arguments.

On the other hand, list derivation may also have some negative effects, that is, the entire list must be loaded into memory at once, which is not a problem for the example above, or even a few more times. But always reach the limit, memory will always run out.

For the above problem, the generator (generator) can be well resolved. Instead of loading the entire list into memory at once, the builder expression generates a Generator object (generator objector), so only one list element is loaded at a time. The

Builder expression has almost the same syntactic structure as a list derivation, except that the builder expression is surrounded by parentheses, not square brackets:

num = [1, 4, -5, ten,-7, 2, 3,-1]
filtered_and_squared = (x**2 for x in num if x > 0)
print filtered_and_squ    Ared
# <generator Object <genexpr> at 0x00583e18> for
item in filtered_and_squared:
Print Item
# 1, 16, 100 4,9


This is a little bit more efficient than list derivation, so let's change the code again:

num = [1, 4, -5, ten,-7, 2, 3,-1]
def square_generator (optional_parameter): Return
(x * * * 2 for x in num If x > Optional_parameter)
print square_generator (0)
# <generator object <genexpr> at 0x004e64  18>
# option I for
K in Square_generator (0):
print K
# 1, MB, 4, 9
# option II
g = List (Square_generator (0))
print G
# [1, 16, 100, 4, 9]


You should often use generator expressions in your code unless you have special reasons. But unless you're facing a very large list, you don't see the obvious difference.

The following example uses the Zip () function to work with elements in two or more lists at once:

alist = [' A1 ', ' A2 ', ' A3 ']
blist = [' 1 ', ' 2 ', ' 3 '] for
A, b in zip (Alist, blist):
print A, b

  # A1 1
# a2 2
# A3 3


Let's take a look at an example of traversing a table of contents through a two-order list:

Import OS
def tree (top): For
path, names, Fnames in Os.walk (top): For
fname in Fnames:
Yield Os.path.join (path, fname) for name in tree
(' C:\Users\XXX\Downloads\Test '):
print Name

 

Adorners (Decorators)

Adorners provide us with an efficient way to increase the functionality of existing functions or classes. Does that sound like a aspect-oriented programming concept in Java? Both are simple, and the adorner has a more powerful function. For example, if you want to do something special (such as security, tracking, and locking operations) at the entry and exit points of a function, you can use adorners.

An adorner is a special function that wraps another function: The main function is invoked, and its return value is passed to the adorner, and the adorner returns an alternate function that wraps the main function, and the other part of the program sees the wrapper function.

def timethis (func):
' decorator that
reports ' execution time.
' Pass
@timethis
def countdown (n): while
n > 0: N-
= 1


The grammar sugar @ identifies the adorner.

Well, let's go back to the example just now. We'll do some more typical things with adorners:

Import time from functools import wraps   Def timethis (func):    
  '     decorator that reports the execution time.      '      @wraps (func)     def wrapper (*args,  **kwargs):         start = time.time ()          result = func (*args, **kwargs)          end = time.time ()         print (func. __name__, end-start)         return result      return wrapper   @timethis Def countdown (n):     while n >  0:         n -= 1   Countdown (100000)   #  (' Countdown ', &NBsp;0.006999969482421875) 


When you write the following code:

@timethis
def countdown (n):

means that you performed the following steps separately:

def countdown (n):
... The code in the
Countdown = Timethis (Countdown)

Adorner function creates a new function (as in this example, the wrapper function), which receives arbitrary input parameters with *args and **kwargs. and calls the original function within this function and returns its result. You can place any additional code (such as the timing operation in this example) according to your needs, and the newly created wrapper function will return as the result and replace the original function.

@decorator
def function ():
    print ("Inside function")

when the compiler views the above code, the function ( function will be compiled, and the function return object will be passed to the adorner code, and the adorner will replace the original function with a new function object after the relevant operation is done. What does the

adorner code look like? Most of the examples are to define adorners as functions, and I find it easier to understand the features of adorners by defining them as classes, and to give more power to the adorner mechanism. The only requirement that

implements a class for an adorner is that it must be able to be used as a function, which means it must be callable. So, if you want to do this, the class must implement the __call__ method. What should an adorner like

use to do? It can do anything, but usually it is used when you want to use the original function in some special place, but this is not necessary, for example:

class decorator (object):       def __
Init__ (self, f):         print ("inside decorator.__init__ ()")         f ()  # prove that function definition  has completed       def __call__ (self):          print ("inside decorator.__call__ ()")   @decorator def function ():   
  print ("Inside function ()")   Print ("Finished decorating function ()")   function ()   # inside decorator.__init__ () # inside function () # finished  Decorating function () # inside decorator.__call__ () 


Translator Note:

1. The syntactic sugar @decorator is equivalent to Function=decorator (function), where decorator __init__ print "Inside decorator.__ Init__ () "

2. Then the F () print" Inside function () "

3. Then execute" print ("finished decorating function ()") "

4. Most After calling the function function, the __call__ print "Inside decorator.__call__ ()" of decorator is performed because of the adorner wrapper. A more practical example of

:

def decorator (func):
def modify (*args, **kwargs):
variable = kwargs.pop (' variable ', None)
Print variable
x,y=func (*args, **kwargs) return
x,y return
modify
@decorator 
  
   def func (a,b):
print a**2,b**2 return a**2,b**2 func (a=4, b=5, variable=
"Hi")
func (a=4, b=5)
# hi #
None
# 16 25
  

  Context Management Library (CONTEXTLIB)

The Contextlib module contains tools related to the context manager and the with Declaration. Usually if you want to write a context manager, you need to define a class that contains __enter__ methods and __exit__ methods, such as:

Import Time
class Demo:
def __init__ (self, label):
self.label = label
def __enter__ ( Self):
Self.start = Time.time ()
def __exit__ (self, exc_ty, Exc_val, EXC_TB): End
= t Ime.time ()
print (' {}: {} '. Format (Self.label, End-self.start))


Complete examples of this:

import time   Class demo:     def
 __init__ (Self, label):         self.label = label       def __enter__ (self):          Self.start = time.time ()       def __exit__ (self, exc_ty, exc_ VAL,&NBSP;EXC_TB):         end = time.time ()   
      print (' {}: {} '. Format (Self.label, end - self.start))   With demo (' Counting '):     n = 10000000     while  n > 0:         n -= 1   # counting :  1.36000013351 


The context manager is activated with a declaration, which involves two methods.

1. The __enter__ method, when the execution stream enters the with code block, the __enter__ method executes. And it returns an object that can be used by the context.

2. When the execution stream leaves the with code block, the __exit__ method is invoked and it cleans up the resource being used.

Rewrite the above example with the @contextmanager adorner:

From contextlib import contextmanager
import time
@contextmanager
def demo (label):
start = time. Time ()
try:
yield
finally: End
= Time.time ()
print (' {}: {} '. Format (Lab El, End-start)) with the
demo (' Counting '):
n = 10000000 while
n > 0:
N-= 1
  
# counting:1.32399988174


Looking at the example above, all the code before yield in the function is similar to the contents of the __enter__ method in the context manager. And all the code after yield is like the content of the __exit__ method. If an exception occurs during execution, it is triggered in the yield statement. The
Descriptor (descriptors)

Descriptor determines how object properties are accessed. The role of the descriptor is to customize what happens when you want to reference an attribute.

The way to build a descriptor is to define at least one of the following three methods. Note that the instance in the following section is an object instance that contains the accessed attribute, while owner is the class that is represented by the descriptor.

    __get__ (self, instance, owner)? This method is invoked when a property is obtained by means of (value = obj.attr). The return value of this method is assigned to the part of the code that requests this property value.
    __set__ (self, instance, value)? This method is called when you want to set the value of the property (obj.attr = ' value '), and the method does not return any values.
    __delete__ (self, instance)? This method is called when a property is deleted from an object (Del obj.attr).

Translator Note: For the understanding of instance and owner, consider the following code:

class Celsius (object):
def __init__ (self, value=0.0):
self.value = float (value)
def __get__ (SE LF, instance, owner): Return
self.value
def __set__ (self, instance, value):
Self.value = f Loat (value)
class Temperature (object):
Celsius = Celsius ()
temp=temperature ()
Temp.celsius #calls celsius.__get__


In the example above, instance refers to temp, while owner is temperature.

Lazyloading Properties Example:

Import weakref   Class lazyattribute (object):     def __init__ (Self, &NBSP;F):         self.data = weakref. Weakkeydictionary ()         self.f = f      def __get__ (SELF,&NBSP;OBJ,&NBSP;CLS):         if obj  not in self.data:              SELF.DATA[OBJ]&NBSP;=&NBSP;SELF.F (obj)         return self.data[ OBJ]   Class foo (object):      @lazyattribute     def bar ( Self):         print  "Being lazy"          return 42   F = foo ()   Print f.bar # being lazy #  42   Print f.bar #  42 


The descriptor is a good summary of the concept of binding methods (bound method) in Python, which is the core of the implementation of classical classes (classic classes). In a classic class, when a property is not found in the dictionary of an object instance, it continues to look in the dictionary of the class, then into the dictionary of the base class, where it is recursively searched. If this property is found in the class dictionary, the interpreter checks to see if the object being found is not a Python function object. If it does, it returns not the object itself, but rather the wrapper object that returns a currying function. When this wrapper is invoked, it first inserts an instance before the argument list and then calls the original function.

Translator Note:

1. Gerty? http://zh.wikipedia.org/wiki/%E6%9F%AF%E9%87%8C%E5%8C%96

2. The difference between Function,method,bound method and unbound method. First, a function is created by a def or a lambda. When a function is defined in a class statement block or created by type, it is converted to an unbound method (unbound), and when this method is accessed through a class instance (instance), it is converted to the binding method (bound methods). The binding method automatically passes the instance as the first argument to the method. In summary, the method is the function that appears in the class, the binding method is a method that binds the concrete instance, and the other is the unbound method.

In summary, the descriptor is assigned to the class, and these special methods are automatically invoked when the property is accessed according to the specific access type.


  Meta Class (Metaclasses)

The Meta class provides an effective way to change the behavior of a Python class.

The definition of a class is "class of a class". Any instance of its own class is a meta class.

class demo (object):     pass   obj =  demo ()   print  "class of obj is {0}". Format (obj.__class__) print  "Class &NBSP;OF&NBSP;OBJ&NBSP;IS&NBSP;{0} ". Format (demo.__class__)   # class of obj is  <class  ' __main__.demo ' > # class of obj is <type  ' type ' 


In the example above, we defined a class demo and generated an object obj for that class. First, you can see that obj's __class__ is demo. Interesting to come, so what is the class of demo? You can see that the __class__ of the demo is type.

So the type is the class of the Python class, in other words, the obj in the example above is a demo object, and the demo itself is an object of type.

So the type is a meta class and is the most common tuple in Python because it makes the default meta class for all classes in Python.

Because the Meta class is the class of the class, it is used to create the class (just as the class is used to create the object). But aren't we creating classes from a standard class definition? That's true, but Python's internal workings are as follows:

    When you see a class definition, Python collects all the attributes into a dictionary.
    when the class definition ends, Python determines the class's meta class, so let's call it meta bar.
    Finally, python execution meta (name, bases, DCT), where:

A. Meta is a meta class, so this call is instantiated.

B. Name is the class name of the new class.

C. Bases is the base class tuple of the new class

D. DCT Maps property names to objects, listing all class properties.

So how do you determine the meta class of a class (a)? In simple terms, if a class (a) itself or one of its base classes (BASE_A) has a __metaclass__ attribute, the Class (A/base_a) is the class (a). Otherwise, type will be the Meta class of Class (A).


Mode (Patterns)

Request forgiveness is easier than requesting permission (EFAP) "

" This Python design principle says, "It's easier to ask for forgiveness than to ask for permission (EFAP)". Do not advocate thoughtful design ideas, the principle is that should try as far as possible, if encountered errors, then give proper treatment. Python has a powerful exception-handling mechanism to support this attempt, which helps programmers develop more stable, fault-tolerant programs. The

Single example

is a single instance object that can exist only at the same time. Python provides a number of ways to implement a single example. The

Null object

Null object can be used instead of the none type to avoid testing for none. The

Observer

Observer mode allows multiple objects to access the same data. The parameters of the

Constructor

Constructor are often assigned to the variables of the instance. This pattern can replace multiple manual assignment statements with one line of code.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.