Some of the features that go into Python function programming _python

Source: Internet
Author: User
Tags closure in python

Binding

Attentive readers may remember the limitations I pointed out in the functional techniques in part 1th. Especially in Python, you cannot avoid a rebind that represents the name of a function expression. In FP, names are often interpreted as abbreviations for longer expressions, but this implies that "the same expression always asks for the same value." This hint is not true if the name of the tag is again bound. For example, let's define some shortcut expressions to use in functional programming, such as:
Listing 1. The following Python FP part of the rebind is going to cause a failure

>>> car = 
    
    Lambda
    
     lst:lst[0]
>>> cdr = 
    
    lambda
    
     lst:lst[1:]
>>> sum2 = 
    
    Lambda
    
     lst:car (LST) +car (CDR (LST))
>>> sum2 (Range ())
1
>>> car = 
    
    Lambda
    
     lst:lst[2]
>>> sum2 (range)
5

Unfortunately, the exact same expression sum2 (range (10)) obtains two different values in the program, even if the expression itself does not use any variable variables in its arguments.

Fortunately, the functional module provides a class called bindings (proposed to Keller) to prevent such a rebind (at least occasionally, Python does not prevent a programmer who wants to unbind). However, the use of bindings requires some extra syntax, so the accident is not easy to happen. In the example of the functional module, Keller names the bindings instance as let (I assume that it is after the given keyword in the ML family language). For example, we would do this:
Listing 2. The Python FP section with secure rebind

>>> 
    
    from
    
     functional 
    
    Import
    
     *
>>> let = bindings ()
>>> Let.car = 
    
    Lambda
    
     lst:lst[0]
>>> let.car = 
    
    Lambda
    
     lst:lst[2]
traceback (innermost last):
 File "<stdin>", line 1, 
    
    in
    
     ?
 File "d:\tools\functional.py", line 976, 
    
    in
    
     __setattr__
  
    
    raise
    
     bindingerror, "Binding '%s ' cannot Be modified. "% name
functional. Bindingerror:binding ' car ' cannot to be modified.
>>> car (range)
0

It is clear that the real program must make some settings to catch "binding errors", and they are thrown away to avoid the emergence of a class of problems.

Together with bindings, functional provides the namespace function to get the namespace from the bindings instance (which is actually a dictionary). This is easy to implement if you want to compute an expression in the (immutable) namespace defined in bindings. The eval () function of Python allows operations to be performed in namespaces. Let's use an example to figure out:
Listing 3. Python FP section using immutable namespaces

>>> let = Bindings ()   
    
    # ' real world ' function names
>>> let.r10 = Range (Ten)
>>> let . Car = 
    
    Lambda
    
     lst:lst[0]
>>> let.cdr = 
    
    Lambda
    
     lst:lst[1:]
>>> eval (' Car ( R10) +car (CDR (R10)) ', namespace (let))
>>> INV = bindings ()   
    
    # "Inverted list" function names
>>> inv.r10 = Let.r10
>>> inv.car = 
    
    Lambda
    
     lst:lst[-1]
>>> inv.cdr =< C17/>lambda
    
     lst:lst[:-1]
>>> eval (' Car (R10) +car (CDR (R10)) ', Namespace (INV))
17

Closed Bag

The FP has an interesting concept-closure. In fact, closures are interesting to many developers, even in a non-functional language such as Perl and Ruby, which includes closures. Also, Python 2.1 is currently trying to incorporate the lexical range restriction feature, which will provide most of the functionality of closures.

What is a closure? Steve Majewski recently provided a good description of this concept in the Python newsgroup:

Objects are data that comes with procedures ... Closures are the process of attaching data.

Closures are like FP's Jekyll for OOP Hyde (roles or swap). Examples of closures like objects are a way to encapsulate a large number of data and functionality together.

Let's go back to the previous place to understand what the objects and closures are all about, and find out how to solve the problem without these two. The result of a function return is often determined by the context in which it is evaluated. The most common-and perhaps most obvious-way to specify a context is to pass some parameters to the function, informing the function what value to handle. But sometimes the "background" and "foreground" parameters are fundamentally different-the difference between what the function is working on at this particular point and the function "configured" for multiple potential invocations.

There are many ways to deal with the background when the focus is on the future. One of these is a simple "bullet-biting" method that passes every parameter required by the function at each call. This approach is usually in the call chain, where a value may be needed in some places, and a value (or struct with a multiple member) is passed. Here's a small example:
Listing 4. Show the Python part of the cargo variable

>>> 
    
    Defa
    
    (n): ...   Add7 = B (n)
...   
    
    Return
    
     add7 ...
>>> 
    
    defb
    
    (n): ...   i = 7
...   j = C (i,n) ...   
    
    Return
    
     J ...
>>> 
    
    DEFC
    
    (i,n): ...   
    
    Return
    
     i+n ...
>>> A (a)   
    
    # Pass cargo value of use downstream
17

In the B () of the cargo example, N has no effect other than the act of passing to C (). Another method will use global variables:
Listing 5. Show the Python part of a global variable

>>> N = ten
>>> 
    
    defaddn
    
    (i):
...   
    
    Global
    
     N
...   
    
    Return
    
     i+n ...
>>> Addn (7)  
    
    # ADD Global N to argument
>>> N =
>>> Addn (6)  
    
    # Ad The D-Global n

to argument global variable N works at any time that you want to invoke Addn (), but it is not necessary to explicitly pass the global background "context". Another, more Python-specific technique is to "freeze" a variable when it is defined into a function that uses default parameters:
listing 6. Python section showing frozen variables

>>> N = ten
>>>< C22/>defaddn
    
    (i, n=n):
...   
    
    Return
    
     i+n ...
>>> Addn (5)  
    
    # add
>>> N =
>>> Addn (6)  
    
    # Add (current N Doe SN ' t matter)
16

Frozen variables are essentially closures. Some data is "subordinate" to the ADDN () function. For a complete closure, when the ADDN () is defined, all data is available at the time of the call. However, in this example (or many more robust examples), using the default parameters can be simple enough. ADDN () A variable that has never been used does not affect its calculation.

Then let's look at an OOP approach that is closer to a real problem. The time of year was reminiscent of the "meet" style of collecting tax procedures for various data-not necessarily in a particular order-and ultimately using all the data to compute. Let's create a simple version:
Listing 7. Python-style Tax calculation class/Example

Class
    
     TaxCalc:
  
    
    deftaxdue
    
    (self):
    
    
    return
    
     (self.income-self.deduct) *self.rate
taxclass = TaxCalc ()
taxclass.income = 50000
taxclass.rate = 0.30 taxclass.deduct
= 10000
    
    print
    
     "Pythonic OOP Taxes Due = ", taxclass.taxdue ()

In the TaxCalc class (or its instance), you can collect some data--in any order--once you have all the elements you need, you can call this object's method to complete the calculation of this large number of data. Everything is in the instance, and the different examples carry different data. The possibility of creating multiple examples and distinguishing their data cannot exist in the global variable or frozen variables method. The "cargo" approach can handle this problem, but for an extended example, we see that it may be necessary to begin passing on various values. Now that we've talked about this, it's also interesting to note how the OPP style of passing messages is handled (Smalltalk or Self is similar to this, some of the OOP xBase variables I use):
Listing 8. Tax calculation for Smalltalk style (Python)

Class
    
     TaxCalc:
  
    
    deftaxdue
    
    (self):
    
    
    return
    
     (self.income-self.deduct) *self.rate
  
    
    Defsetincome
    
    (self,income):
    self.income = income
    
    
    return
    
     self
  
    
    defsetdeduct
    
    (self, Deduct):
    self.deduct = deduct
    
    
    return
    
     self
  
    
    defsetrate
    
    (self,rate):
    self.rate = Rate
    
    
    return
    
     self
    
    print
    
     "smalltalk-style taxes due =", \
   TaxCalc (). Setincome (50000). Setrate ( 0.30). Setdeduct (10000). Taxdue ()

Returning self with each "setter" allows us to think of "existing" as the result of the application of each method. This has many interesting similarities with the FP closure method.

With the Xoltar Toolkit, we can create a complete closure with the desired combination of data and function attributes, while allowing multiple segments of closures (nee Objects) to contain different packages:
Listing 9. The tax calculation of Python function style

From
    
     functional 
    
    Import
    
     *
taxdue    = 
    
    Lambda
    
    : (income-deduct) *rate
incomeclosure = 
    
    Lambda
    
     income,taxdue:closure (taxdue)
deductclosure = 
    
    Lambda
    
     deduct,taxdue:closure ( Taxdue)
rateclosure  = 
    
    Lambda
    
     rate,taxdue:closure (taxdue)
taxfp =
taxdue TAXFP = Incomeclosure (50000,TAXFP)
TAXFP = Rateclosure (0.30,TAXFP)
TAXFP = Deductclosure (10000,TAXFP)
    
    Print
    
     "functional Taxes Due =", TAXFP ()
    
    print
    
     "lisp-style taxes =", \
   Due (incomeclosure,
     Rateclosure (0.30,
       deductclosure (10000, Taxdue))) ()

Each closure function we define carries with it any value defined within the scope of the function, and then binds the values to the global scope of the function object. However, the global scope of a function does not appear to be the same as the global scope of the actual module, and is not the same as the global scope of the different closures. Closures simply "carry data".

In the example, we used special functions to put specific bindings within the closure scope (income, deduct, rate). Modifying the design to put any bindings within the range is also very simple. We can also use the nuances of different function styles in the example, but it's just for fun. The first succeeds in binding the value added to the closure scope, making the TAXFP variable, and these "add to closure" rows can appear in any order. However, if you want to use immutable names such as Tax_with_income, you must arrange the bound rows in a certain order, and then pass the preceding binding to the next. In any case, once all that is required is bound into the closure, we call the "seeded" function.

The second style looks closer to Lisp (more like parentheses to me). If you don't consider beauty, two interesting things happen in the second style. The first is that the name bindings are completely avoided. The second style is a single expression without statements (see part 1th, to discuss why this can be a problem).

Another interesting example of the use of "Lisp-style" closures is how much similar to the "Smalltalk style" messaging method mentioned above. Both accumulate values and invoke the Taxdue () function/method (both of which will have an error in these original versions if there is no correct data). "Smalltalk style" passes objects between each step, and "Lisp style" passes a continuous. But for a deeper understanding, most of the functions and object-oriented programming are like this.

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.