程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

21. Python functions (VI) [second half of functional programming]

編輯:Python

Catalog :

  • Each preface :
  • Python function ( 6、 ... and )
    • 1.1 Functional programming
      • 1.1.1 Closure
      • 1.1.2 Decorator
      • 1.1.3 Partial function

Each preface :

  • The authors introduce :【 Lonely and cold 】—CSDN High quality creators in the whole stack field 、HDZ Core group members 、 Huawei cloud sharing expert Python Full stack domain bloggers 、CSDN The author of the force program

  • This article has been included in Python Full stack series column :《Python Full stack basic tutorial 》
  • Popular column recommendation :《Django Framework from the entry to the actual combat 》、《 A series of tutorials from introduction to mastery of crawler 》、《 Reptile advanced 》、《 Front end tutorial series 》、《tornado A dragon + A full version of the project 》.
  • ​ This column is for the majority of program users , So that everyone can do Python From entry to mastery , At the same time, there are many exercises , Consolidate learning .
  • After subscribing to the column But there are more than 1000 people talking privately Python Full stack communication group ( Teaching by hand , Problem solving ); Join the group to receive Python Full stack tutorial video + Countless computer books : Basics 、Web、 Reptiles 、 Data analysis 、 visualization 、 machine learning 、 Deep learning 、 Artificial intelligence 、 Algorithm 、 Interview questions, etc .
  • Join me to learn and make progress , One can walk very fast , A group of people can go further !

Python function ( 6、 ... and )

1.1 Functional programming

1.1.1 Closure

  • Notice in the last article 【 Function as return value 】 The function returned in that section references a local variable inside its definition args, therefore , When a function returns a function , Its internal local variables are also referenced by new functions , therefore , Closures are easy to use , It's not easy to implement .
  • Another problem that needs attention is , The returned function did not execute immediately , But until the call f() To perform . Let's take an example :
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
  • In the example above , Each cycle , All created a new function , then , To create the 3 All functions return .
    You might think that calling f1(),f2() and f3() The result should be 1,4,9, But the actual result is :
>>> f1()
9
>>> f2()
9
>>> f3()
9
  • All of them are 9! The reason is that the returned function references the variable i, But it's not implemented immediately . wait until 3 When all functions return , The variables they reference i Has become 3, So the end result is 9.
  • One thing to keep in mind when returning to closures is : Return functions do not reference any loop variables , Or variables that will change in the future .
  • What if you have to reference a loop variable ? By creating another function , Bind the current value of the loop variable with the parameter of this function , No matter how the loop variable changes later , The value bound to the function parameter does not change :
def count():
fs = []
for i in range(1, 4):
def f(j):
def g():
return j*j
return g
fs.append(f(i))
return fs
>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9
  • The disadvantage is that the code is long , available lambda Expression shortening code :
# -*- coding: utf-8 -*-
""" __author__ = Xiaoming - Code entities """
def count():
fs = []
for i in range(1, 4):
f = lambda j: (lambda: j * j)
fs.append(f(i))
return fs
f1, f2, f3 = count()
print(f1(), f2(), f3())

1.1.2 Decorator

The complete examples used are explained below :

import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
  • The function object has a __name__ attribute , You can get the name of the function :
>>> def now():
... print('2015-3-25')
...
>>> now.__name__
'now'
  • Now? , Suppose we want to enhance now() Function functions , such as , Automatically print log before and after function call , But I don't want to modify now() Definition of function , This way of dynamically adding functions during code execution , be called “ Decorator ”(Decorator).
  • Essentially ,decorator It's a higher-order function that returns a function . therefore , We want to define a... That can print logs decorator, It can be defined as follows :
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
  • wrapper() The parameter definition of the function is (*args, **kw), therefore ,wrapper() Function can accept any parameter call .
  • Look at the top log, Because it's a decorator, So take a function as an argument , And return a function . We have to resort to Python Of @ grammar , hold decorator In the definition of the function :
@log
def now():
print('2015-3-25')
  • hold @log Put it in now() Where the function is defined , It's equivalent to executing a statement :
now = log(now)
  • call now() function , Not only will it run now() The function itself , It's still running now() Print a line of log before function :
>>> now()
call now():
2015-3-25
  • If decorator The parameter itself needs to be passed in , Then you need to write a return decorator The higher-order function of , It's more complicated to write . such as , To customize log The text of :
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
  • This 3 Layers nested decorator Usage is as follows :
@log('execute')
def now():
print('2015-3-25')
  • And two layers of nested decorator comparison ,3 This is the effect of layer nesting :
>>> now = log('execute')(now)

The results are as follows :

>>> now()
execute now():
2015-3-25
  • Two of the above decorator There's no problem with the definition of , But after decorator Function after decoration , Their __name__ Already from the original ’now’ Turned into ’wrapper’:
>>> now.__name__
'wrapper'
  • Python Built in functools.wraps Can achieve wrapper.name = func.__name__ The effect of , therefore , A complete decorator Let's write it as follows :

Explain that :Python Decorator (decorator) At the time of realization , The decorated function is actually another function ( Function properties such as function name will change , For example, you will find that the function name has changed to wrapper), In order not to affect ,Python Of functools There is a package called wraps Of decorator To eliminate such side effects . Write a decorator When , It's better to add functools Of wrap, It can keep the original function name and function properties

import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
  • Or for parameters decorator:
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
  • practice
    To design a decorator, It works on any function , And print the execution time of the function , You can calculate the execution time of any function :
# -*- coding: utf-8 -*-
""" __author__ = Xiaoming - Code entities """
import functools, time
def metric(fn):
@functools.wraps(fn)
def wrapper(*args, **kw):
start_time = time.time() * 1000
result = fn(*args, **kw)
run_time = time.time() * 1000 - start_time
print('%s executed in %s ms' % (fn.__name__, run_time))
return result
return wrapper
@metric
def fast(x, y):
time.sleep(0.003)
return x + y
@metric
def slow(x, y, z):
time.sleep(0.1257)
return x * y * z
f = fast(11, 22)
s = slow(11, 22, 33)

1.1.3 Partial function

  • Suppose you want to convert a large number of binary strings , Every time it comes in int(x, base=2) Very trouble , therefore , We think of , You can define a int2() Function of , By default base=2 Pass in :
def int2(x, base=2):
return int(x, base)
  • functools.partial You can create a partial function , We don't need to define int2(), You can create a new function directly using the following code int2:
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
  • When creating partial functions , You can actually receive function objects 、*args and **kw this 3 Parameters , When it comes to :
int2 = functools.partial(int, base=2)
  • It's actually fixed int() Function's key argument base, That is to say :
int2('10010')
  • amount to :
kw = {
 'base': 2 }
int('10010', **kw)
  • When it comes to :
max2 = functools.partial(max, 10)
  • In fact, it will put 10 As *args Part of is automatically added to the left , That is to say :
max2(5, 6, 7)
  • amount to :
args = (10, 5, 6, 7)
max(*args)
  • The result is 10.

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved