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

[python] first class function

編輯:Python

《 smooth Python》 Luciano · Ramallo The first 5 Chapter   The wait function Reading notes

Catalog

5.1 Treat functions as objects

5.2 Higher order function

5.3 Anonymous functions

5.4 Callable object

5.5 User defined callable types

5.6 Functional introspection

5.7 From locating parameters to keyword only parameters

5.10 Packages supporting functional programming

5.10.1 operator modular

5.10.2 Use functools.partial Freeze parameters


stay Python in , Functions are first-class objects . Programming language theorists “ First class object ” Defined as a procedural entity that meets the following conditions :
- Create at run time
- Can be assigned to an element in a variable or data structure
- Can be passed to a function as a parameter
- Can be the return result of a function
stay Python in , Integers 、 Strings and dictionaries are first-class objects .
People often will “ Treat functions as first-class objects ” Referred to as “ The wait function ”.

5.1 Treat functions as objects

>>> def factorial(n):
...     '''returns n!'''
...     return 1 if n < 2 else n * factorial(n-1)
...
>>> factorial(42)
1405006117752879898543142606244511569936384000000000
>>>
>>> type(factorial)
<class 'function'>
>>>

Use functions by other names , Then pass the function as a parameter

>>> fact = factorial
>>> fact
<function factorial at 0x7f8f484de940>
>>>
>>> fact(5)
120
>>>

5.2 Higher order function

Accept a function as an argument , Or the function returned as a result is a higher-order function (higher order function).map Function is an example ; Built in functions sorted It's also : Optional key Parameters are used to provide a function , It will be applied to all
Sort on elements .
【 example 】 Sort according to the length of words , Just put len Function to key Parameters

>>> fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
>>> sorted(fruits, key=len)
['fig', 'apple', 'cherry', 'banana', 'raspberry', 'strawberry']
>>>

Any single parameter function can be used as key The value of the parameter . for example , To create a rhyming dictionary , You can spell each word in reverse , Then sort .

>>> def reverse(word):
... return word[::-1]
...
>>> sorted(fruits, key=reverse)
['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']
>>>

In the functional programming paradigm , The most well-known higher-order functions are map、filter、reduce.

stay Python 3 in ,map and filter Or built-in functions . List derivation or generator expression has map and filter The function of two functions , And it's easier to read .

【 example 】 Calculate factorial list :map and filter Compare with list derivation

>>> map(factorial,range(11))
<map object at 0x7f8f485088e0>
>>>
>>> list(map(fact,range(11)))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
>>>
>>> [fact(n) for n in range(11)]
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
>>>
>>> list(map(fact,filter(lambda n: n%2, range(6))))
[1, 6, 120]
>>>
>>> [fact(n) for n in range(6) if n%2]
[1, 6, 120]
>>>

explain : stay Python 3 in ,map and filter Return to generator ( An iterator ), So now their direct replacement is generator expressions .

stay Python 2 in ,reduce It's a built-in function , But in Python 3 Put in functools In the module , This function is most commonly used to sum .

【 example 】 Use reduce and sum Calculation 0~99 The sum of the

>>> from functools import reduce
>>> from operator import add
>>> reduce(add, range(100))
4950
>>>

all and any It is also a built-in reduction function
all(iterable)   If iterable Every element of is a true value , return True;all([]) return True.
any(iterable)   as long as iterable There are elements in that are true values , Just go back to True;any([]) return False.

5.3 Anonymous functions

In addition to being passed as parameters to higher-order functions ,Python Anonymous functions are rarely used . It is best used in the parameter list .
【 example 】 Use lambda Expression reverse spelling , Then sort the word list according to this

>>> fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
>>> sorted(fruits, key=lambda word: word[::-1])
['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']
>>>

5.4 Callable object

In addition to user-defined functions , Call operator -> namely ()   It can also be applied to other objects . If you want to determine whether an object can call , You can use the built-in callable() function .Python The data model document lists 7 Kinds of callable objects .
(1) User defined functions
Use def Sentence or lambda Expression creation .

(2) Built in functions
Use C Language (CPython) Implemented function , Such as len or time.strftime.

(3) Built-in methods
Use C Methods of language implementation , Such as dict.get.

(4) Method
Functions defined in the definition body of a class .

(5) class
When calling a class, it will run the class __new__ Method to create an instance , And then run __init__ Method , Initialize instance , Finally, return the instance to the caller .

(6) Class
If the class defines __call__ Method , Then its instance can be called as a function .

(7) Generator function
Use yield Function or method of keyword . Calling the generator function returns the generator object .

Python There are various types that can be called in , Therefore, judge whether the object can call , The safest way is to use the built-in callable() function :

>>> abs, str, 13
(<built-in function abs>, <class 'str'>, 13)
>>> [callable(obj) for obj in (abs, str, 13)]
[True, True, False]
>>>

5.5 User defined callable types

whatever Python Objects can behave like functions , Just implement the instance method __call__.

【 example 】bingocall.py, BingoCage An instance of the class is built using any iteratible object , And it will store a list in random order inside .

import random
class BingoCage:
def __init__(self, items):
self._items = list(items)
random.shuffle(self._items)
def pick(self):
try:
return self._items.pop()
except IndexError:
raise LookupError('pick from empty BingoCage')
def __call__(self):
return self.pick()

explain :

__init__ Accept any iteratable object

bingo.pick() The shortcut is bingo()

5.6 Functional introspection

Use dir Function can detect factorial It has the following properties , Most of these properties are Python Objects share

>>> def factorial(n):
... '''returns n!'''
... return 1 if n < 2 else n * factorial(n-1)
...
>>>
>>> dir(factorial)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>>

【 example 】 List properties that regular objects do not have but functions do

>>> class C: pass
...
>>> obj = C()
>>> def func(): pass
...
>>> sorted(set(dir(func)) - set(dir(obj)))
['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__']
>>>

5.7 From locating parameters to keyword only parameters

Example 5-10 tag The function is used to generate HTML label ; Use the name cls The keyword parameter of is passed in "class" attribute , Because " class" yes Python Key words of

def tag(name, *content, cls=None, **attrs):
""" Generate one or more HTML label """
if cls is not None:
attrs['class'] = cls
if attrs:
attr_str = ''.join(' %s="%s"' % (attr, value)
for attr, value in sorted(attrs.items()))
else:
attr_str = ''
if content:
return '\n'.join('<%s%s>%s</%s>' %
(name, attr_str, c, name) for c in content)
else:
return '<%s%s />' % (name, attr_str)

Example 5-11 tag Several of the numerous call methods of functions

>>> tag('br') #1
'<br />'
>>> tag('p', 'hello') #2
'<p>hello</p>'
>>> tag('p', 'hello', 'world') #2
'<p>hello</p>\n<p>world</p>'
>>> print(tag('p', 'hello', 'world'))
<p>hello</p>
<p>world</p>
>>>
>>> tag('p', 'hello', id=33) #3
'<p id="33">hello</p>'
>>>
>>> print(tag('p', 'hello', 'world', cls='sidebar')) #4
<p class="sidebar">hello</p>
<p class="sidebar">world</p>
>>>
>>> tag(content='testing', name="img") #5
'<img content="testing" />'
>>>
>>> my_tag = {'name': 'img', 'title': 'Sunset Boulevard', 'src': 'sunset.jpg', 'cls':'framed'}
>>> tag(**my_tag)
'<img class="framed" src="sunset.jpg" title="Sunset Boulevard" />'
>>>

explain :

#1 Pass in a single location parameter , Generate an empty label with the specified name .
#2 Any parameter after the first parameter will be *content Capture , Save a tuple .
#3 Keyword parameters without an explicit name are **attrs Capture , Put it in a dictionary .
#4 cls Parameters can only be passed in as keyword parameters .
#5 call tag Function time , Even the first positioning parameter can be passed in as a keyword parameter .
#6 stay my_tag prefix **, All elements in the dictionary are passed in as a single parameter , The key with the same name will be bound to the corresponding named parameter , The rest is **attrs Capture .

Only keyword parameters are Python 3 New features . In the example 5-10 in ,cls Parameters can only be specified by keyword parameters , It must not capture unnamed positioning parameters .
When defining a function, if you want to specify keyword only parameters , To put them in front, there are * After the parameter of .
If you don't want to support an indefinite number of positioning parameters , But I want to support keyword only parameters , Put one in the signature *, As shown below :

>>> def f(a, *, b):
... return a,b
...
>>> f(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1,b=2)
(1, 2)
>>>

Be careful , Keyword only parameters don't have to have default values , It can be like the above example b like that , Mandatory argument must be passed in

5.10 Packages supporting functional programming

5.10.1 operator modular

In functional programming , It is often necessary to use arithmetic operators as functions . for example , Do not use recursion to calculate factorials . Summation can use sum function , But quadrature doesn't have such a function .
We can use reduce function , But you need a function to calculate the product of two elements in the sequence .

(1)mul

Example 5-21 Use reduce Function and an anonymous function calculate factorials

from functools import reduce
def fact(n):
    return reduce(lambda a, b: a*b, range(1, n+1))

operator The module provides corresponding functions for multiple arithmetic operators , So as to avoid writing anonymous functions .

Example 5-22 Use reduce and operator.mul Function calculates factorial

from functools import reduce
from operator import mul
def fact(n):
return reduce(mul, range(1, n+1))

(2)itemgetter

itemgetter Common USES : Sort the tuple list according to a field of tuples . In the following example , According to the country code ( The first 2 A field ) Print the information of each city in order . Actually ,itemgetter(1) The role of lambda fields: fields[1] equally , Create a function that accepts a collection , Return index bit 1 On the element .

Example 5-23 Demonstrate the use of itemgetter Sort a tuple list

>>> metro_data = [
... ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
... ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
... ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
... ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
... ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
... ]
>>> from operator import itemgetter
>>> for city in sorted(metro_data, key=itemgetter(1)):
... print(city)
...
('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833))
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889))
('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
('Mexico City', 'MX', 20.142, (19.433333, -99.133333))
('New York-Newark', 'US', 20.104, (40.808611, -74.020386))
>>>

If you pass multiple parameters to itemgetter, The function it builds will return tuples of extracted values :

>>> cc_name = itemgetter(1, 0)
>>> for city in metro_data:
... print(cc_name(city))
...
('JP', 'Tokyo')
('IN', 'Delhi NCR')
('MX', 'Mexico City')
('US', 'New York-Newark')
('BR', 'Sao Paulo')
>>>

itemgetter Use [] Operator , So it not only supports sequences , It also supports mapping and any implementation __getitem__ Class of method .

(3)attrgetter

attrgetter And itemgetter Works in a similar way , it The created function extracts the attributes of the object according to the name . If you pass multiple attribute names to attrgetter, It also returns tuples of extracted values . Besides , If the parameter name contains .( Order number ),attrgetter Will drill down into nested objects , Get the specified properties .

Example 5-24 Define a be known as metro_data Of namedtuple, Use attrgetter Deal with it

>>> from collections import namedtuple
>>> LatLong = namedtuple('LatLong', 'lat long') #1
>>> Metropolis = namedtuple('Metropolis', 'name cc pop coord') #2
>>> metro_areas = [Metropolis(name, cc, pop, LatLong(lat, long)) #3
... for name, cc, pop, (lat, long) in metro_data]
>>>
>>> metro_areas[0]
Metropolis(name='Tokyo', cc='JP', pop=36.933, coord=LatLong(lat=35.689722, long=139.691667))
>>>
>>> metro_areas[0].coord
LatLong(lat=35.689722, long=139.691667)
>>> metro_areas[0].coord.lat #4
35.689722
>>>
--------------------------------------------------------------------------
>>> from operator import attrgetter
>>> name_lat = attrgetter('name', 'coord.lat') #5
>>> for city in sorted(metro_areas, key=attrgetter('coord.lat')): #6
... print(name_lat(city)) #7
...
('Sao Paulo', -23.547778)
('Mexico City', 19.433333)
('Delhi NCR', 28.613889)
('Tokyo', 35.689722)
('New York-Newark', 40.808611)
>>>

explain :

#1 Use namedtuple Definition LatLong.
#2 Redefine Metropolis.
#3 Use Metropolis Case construction metro_areas list ; Be careful , We use nested tuples to unpack and extract (lat, long), Then use them to build LatLong, As Metropolis Of coord attribute .
#4 thorough metro_areas[0], Get its latitude .
#5 Define a attrgetter, obtain name Properties and nested coord.lat attribute .
#6 Again using attrgetter, Sort the list of cities by latitude .
#7 Use the label 5 As defined in attrgetter, Show only city name and latitude .

Here are operator Some functions defined in the module ( Omitted with _ The name at the beginning )

>>> import operator
>>> [name for name in dir(operator) if not name.startswith('_')]
['abs', 'add', 'and_', 'attrgetter', 'concat', 'contains', 'countOf', 'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd', 'iand', 'iconcat', 'ifloordiv', 'ilshift', 'imatmul', 'imod', 'imul', 'index', 'indexOf', 'inv', 'invert', 'ior', 'ipow', 'irshift', 'is_', 'is_not', 'isub', 'itemgetter', 'itruediv', 'ixor', 'le', 'length_hint', 'lshift', 'lt', 'matmul', 'methodcaller', 'mod', 'mul', 'ne', 'neg', 'not_', 'or_', 'pos', 'pow', 'rshift', 'setitem', 'sub', 'truediv', 'truth', 'xor']
>>>

explain : With i start 、 Followed by the names of another operator ( Such as iadd、iand etc. ), Corresponding to the incremental assignment operator ( Such as +=、&= etc. ). If the first parameter is variable , Then these operator functions will modify it in place ; otherwise , Function and without i The function is the same as , Directly return the result of operation .

(4)methodcaller

methodcaller The role of attrgetter and itemgetter similar , It will create its own functions .methodcaller The created function will call the method specified by the parameter on the object .

Example 5-25 methodcaller Examples of use

# The first test is just to show methodcaller Usage of , If you want to put the str.upper Use as a function ,
# Just in str Class call , And pass in a string parameter ,str.upper(s)
>>> from operator import methodcaller
>>> s = 'The time has come'
>>> upcase = methodcaller('upper')
>>> upcase(s)
'THE TIME HAS COME'
>>>
# The second test shows ,methodcaller You can also freeze some parameters ,
# That is, some applications (partial application), This is related to functools.partial The function works like .
>>> hiphenate = methodcaller('replace', ' ', '-')
>>> hiphenate(s)
'The-time-has-come'
>>>

5.10.2 Use functools.partial Freeze parameters

functools In the higher-order function proposed by the module , Perhaps the most well-known is reduce. Among the remaining functions , The most useful thing is
partial And its variants ,partialmethod.
functools.partial This higher-order function is used to partially apply a function . Some applications refer to , Create a new callable object based on a function , Fix some parameters of the original function . Using this function, you can adapt a function that accepts one or more parameters to a function that needs a callback API, So there are fewer parameters .

functools.partialmethod function (Python 3.4 newly added ) The role of partial equally , It's just for processing .

Example 5-26 Use partial Adapt a two parameter function into a callable object that requires a single parameter

>>> from operator import mul
>>> from functools import partial
>>> triple = partial(mul, 3) # Use mul establish triple function , Set the first positioning parameter as 3
>>> triple(6)
18
>>> list(map(triple, range(1, 10)))
[3, 6, 9, 12, 15, 18, 21, 24, 27]
>>>

Example 5-28 hold partial Apply to the example 5-10 Medium tag On the function , Freeze a positioning parameter and a keyword parameter .

>>> from functools import partial
>>> picture = partial(tag, 'img', cls='pic-frame') #1
>>> picture(src='Spongebob.jpg')
'<img class="pic-frame" src="Spongebob.jpg" />'
>>>
>>> picture
functools.partial(<function tag at 0x7f7fcb02a5e0>, 'img', cls='pic-frame') #2
>>> picture.func #3
<function tag at 0x7f7fcb02a5e0>
>>> tag
<function tag at 0x7f7fcb02a5e0>
>>>
>>>
>>> picture.args #3
('img',)
>>> picture.keywords #3
{'cls': 'pic-frame'}
>>>

explain :
#1 Use tag establish picture function , Fix the first positioning parameter as 'img', hold cls The keyword parameter is fixed to 'pic-frame'.
#2 partial() Return to one functools.partial object .
#3 functools.partial Object provides properties to access the original function and fixed parameters .


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