Python函数式编程备忘录

3,461次阅读
没有评论

引言

functools, itertools, operator是Python标准库为我们提供的支持函数式编程的三大模块,合理的使用这三个模块,我们可以写出更加简洁可读的Pythonic代码,接下来我们通过一些example来了解三大模块的使用。

functools的使用

functools是Python中很重要的模块,它提供了一些非常有用的高阶函数。高阶函数就是说一个可以接受函数作为参数或者以函数作为返回值的函数,因为Python中函数也是对象,因此很容易支持这样的函数式特性

partial

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> partial

<span class="hljs-prompt">>>> </span>basetwo = partial(int, base=<span class="hljs-number">2</span>)

<span class="hljs-prompt">>>> </span>basetwo(<span class="hljs-string">'10010'</span>)
<span class="hljs-number">18</span>

basetwo('10010')实际上等价于调用int('10010', base=2),当函数的参数个数太多的时候,可以通过使用functools.partial来创建一个新的函数来简化逻辑从而增强代码的可读性,而partial内部实际上就是通过一个简单的闭包来实现的

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">partial</span><span class="hljs-params">(func, *args, **keywords)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">newfunc</span><span class="hljs-params">(*fargs, **fkeywords)</span>:</span>
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        <span class="hljs-keyword">return</span> func(*args, *fargs, **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    <span class="hljs-keyword">return</span> newfunc

partialmethod

partialmethod和partial类似,但是对于绑定一个非对象自身的方法的时候,这个时候就只能使用partialmethod了,我们通过下面这个例子来看一下两者的差异

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> partial, partialmethod

<span class="hljs-prompt">>>> </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">standalone</span><span class="hljs-params">(self, a=<span class="hljs-number">1</span>, b=<span class="hljs-number">2</span>)</span>:</span>
<span class="hljs-prompt">... </span>    <span class="hljs-string">"Standalone function"</span>
<span class="hljs-prompt">... </span>    print(<span class="hljs-string">'  called standalone with:'</span>, (self, a, b))
<span class="hljs-prompt">... </span>    <span class="hljs-keyword">if</span> self <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">None</span>:
<span class="hljs-prompt">... </span>        print(<span class="hljs-string">'  self.attr ='</span>, self.attr)

<span class="hljs-prompt">>>> </span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyClass</span>:</span>
<span class="hljs-prompt">... </span>    <span class="hljs-string">"Demonstration class for functools"</span>
<span class="hljs-prompt">... </span>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-prompt">... </span>        self.attr = <span class="hljs-string">'instance attribute'</span>
<span class="hljs-prompt">... </span>    method1 = functools.partialmethod(standalone)  <span class="hljs-comment"># 使用partialmethod</span>
<span class="hljs-prompt">... </span>    method2 = functools.partial(standalone)  <span class="hljs-comment"># 使用partial</span>

<span class="hljs-prompt">>>> </span>o = MyClass()

<span class="hljs-prompt">>>> </span>o.method1()
  called standalone <span class="hljs-keyword">with</span>: (<__main__.MyClass object at <span class="hljs-number">0x7f46d40cc550</span>>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
  self.attr = instance attribute

<span class="hljs-comment"># 不能使用partial</span>
<span class="hljs-prompt">>>> </span>o.method2()
Traceback (most recent call last):
  File <span class="hljs-string">"<stdin>"</span>, line <span class="hljs-number">1</span>, <span class="hljs-keyword">in</span> <module>
TypeError: standalone() missing <span class="hljs-number">1</span> required positional argument: <span class="hljs-string">'self'</span>

singledispatch

虽然Python不支持同名方法允许有不同的参数类型,但是我们可以借用singledispatch来动态指定相应的方法所接收的参数类型,而不用把参数判断放到方法内部去判断从而降低代码的可读性

<span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> singledispatch


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestClass</span><span class="hljs-params">(object)</span>:</span>
    <span class="hljs-decorator">@singledispatch</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_method</span><span class="hljs-params">(arg, verbose=False)</span>:</span>
        <span class="hljs-keyword">if</span> verbose:
            print(<span class="hljs-string">"Let me just say,"</span>, end=<span class="hljs-string">" "</span>)
        print(arg)

    <span class="hljs-decorator">@test_method.register(int)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_</span><span class="hljs-params">(arg)</span>:</span>
        print(<span class="hljs-string">"Strength in numbers, eh?"</span>, end=<span class="hljs-string">" "</span>)
        print(arg)

    <span class="hljs-decorator">@test_method.register(list)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_</span><span class="hljs-params">(arg)</span>:</span>
        print(<span class="hljs-string">"Enumerate this:"</span>)

        <span class="hljs-keyword">for</span> i, elem <span class="hljs-keyword">in</span> enumerate(arg):
            print(i, elem)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    TestClass.test_method(<span class="hljs-number">55555</span>)  <span class="hljs-comment"># call @test_method.register(int)</span>
    TestClass.test_method([<span class="hljs-number">33</span>, <span class="hljs-number">22</span>, <span class="hljs-number">11</span>])   <span class="hljs-comment"># call @test_method.register(list)</span>
    TestClass.test_method(<span class="hljs-string">'hello world'</span>, verbose=<span class="hljs-keyword">True</span>)  <span class="hljs-comment"># call default</span>

根据运行结果来解释一下上面这段代码,上面通过@test_method.register(int)和@test_method.register(list)指定当test_method的第一个参数为int或者list的时候,分别调用不同的方法来进行处理

Enumerate this:
<span class="hljs-number">0</span> <span class="hljs-number">33</span>
<span class="hljs-number">1</span> <span class="hljs-number">22</span>
<span class="hljs-number">2</span> <span class="hljs-number">11</span>
Let me just say, hello world

wraps

装饰器会遗失被装饰函数的__name__和__doc__等属性,可以使用@wraps来恢复

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> wraps

<span class="hljs-prompt">>>> </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">my_decorator</span><span class="hljs-params">(f)</span>:</span>
<span class="hljs-prompt">... </span>    <span class="hljs-decorator">@wraps(f)</span>
<span class="hljs-prompt">... </span>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span><span class="hljs-params">()</span>:</span>
<span class="hljs-prompt">... </span>        <span class="hljs-string">"""wrapper_doc"""</span>
<span class="hljs-prompt">... </span>        print(<span class="hljs-string">'Calling decorated function'</span>)
<span class="hljs-prompt">... </span>        <span class="hljs-keyword">return</span> f()
<span class="hljs-prompt">... </span>    <span class="hljs-keyword">return</span> wrapper
...

<span class="hljs-prompt">>>> </span><span class="hljs-decorator">@my_decorator</span>
<span class="hljs-prompt">... </span><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">example</span><span class="hljs-params">()</span>:</span>
<span class="hljs-prompt">... </span>    <span class="hljs-string">"""example_doc"""</span>
<span class="hljs-prompt">... </span>    print(<span class="hljs-string">'Called example function'</span>)
...

<span class="hljs-prompt">>>> </span>example.__name__
<span class="hljs-string">'example'</span>
<span class="hljs-prompt">>>> </span>example.__doc__
<span class="hljs-string">'example_doc'</span>

<span class="hljs-comment"># 尝试去掉@wraps(f)来看一下运行结果,example自身的__name__和__doc__都已经丧失了</span>
<span class="hljs-prompt">>>> </span>example.__name__
<span class="hljs-string">'wrapper'</span>
<span class="hljs-prompt">>>> </span>example.__doc__
<span class="hljs-string">'wrapper_doc'</span>

我们也可以使用update_wrapper来改写

<span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> update_wrapper

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">g</span><span class="hljs-params">()</span>:</span>
    ...
g = update_wrapper(g, f)

<span class="hljs-comment"># 等价于</span>
<span class="hljs-decorator">@wraps(f)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">g</span><span class="hljs-params">()</span>:</span>
    ...

@wraps内部实际上就是基于update_wrapper来实现的

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wraps</span><span class="hljs-params">(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decorator</span><span class="hljs-params">(wrapper)</span>:</span>
        <span class="hljs-keyword">return</span> update_wrapper(wrapper, wrapped=wrapped...)
    <span class="hljs-keyword">return</span> decorator

total_ordering

Python2中可以通过自定义__cmp__的返回值0/-1/1来比较对象的大小,在Python3中废弃了__cmp__,但是我们可以通过total_ordering然后修改 __lt__() , __le__() , __gt__(), __ge__(), __eq__(), __ne__() 等魔术方法来自定义类的比较规则。p.s: 如果使用必须在类里面定义 __lt__() , __le__() , __gt__(), __ge__()中的一个,以及给类添加一个__eq__() 方法

<span class="hljs-keyword">import</span> functools


<span class="hljs-decorator">@functools.total_ordering</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyObject</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, val)</span>:</span>
        self.val = val

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__eq__</span><span class="hljs-params">(self, other)</span>:</span>
        print(<span class="hljs-string">'  testing __eq__({}, {})'</span>.format(
            self.val, other.val))
        <span class="hljs-keyword">return</span> self.val == other.val

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__gt__</span><span class="hljs-params">(self, other)</span>:</span>
        print(<span class="hljs-string">'  testing __gt__({}, {})'</span>.format(
            self.val, other.val))
        <span class="hljs-keyword">return</span> self.val > other.val


a = MyObject(<span class="hljs-number">1</span>)
b = MyObject(<span class="hljs-number">2</span>)

<span class="hljs-keyword">for</span> expr <span class="hljs-keyword">in</span> [<span class="hljs-string">'a < b'</span>, <span class="hljs-string">'a <= b'</span>, <span class="hljs-string">'a == b'</span>, <span class="hljs-string">'a >= b'</span>, <span class="hljs-string">'a > b'</span>]:
    print(<span class="hljs-string">'\n{:<6}:'</span>.format(expr))
    result = eval(expr)
    print(<span class="hljs-string">'  result of {}: {}'</span>.format(expr, result))

下面是运行结果

a < b :
  testing __gt__(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
  testing __eq__(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
  result of a < b: <span class="hljs-keyword">True</span>

a <= b:
  testing __gt__(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
  result of a <= b: <span class="hljs-keyword">True</span>

a == b:
  testing __eq__(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
  result of a == b: <span class="hljs-keyword">False</span>

a >= b:
  testing __gt__(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
  testing __eq__(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
  result of a >= b: <span class="hljs-keyword">False</span>

a > b :
  testing __gt__(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
  result of a > b: <span class="hljs-keyword">False</span>

itertools的使用

itertools为我们提供了非常有用的用于操作迭代对象的函数

无限迭代器

count

count(start=0, step=1) 会返回一个无限的整数iterator,每次增加1。可以选择提供起始编号,默认为0

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> count

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> zip(count(<span class="hljs-number">1</span>), [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]):
<span class="hljs-prompt">... </span>    print(i, end=<span class="hljs-string">' '</span>)
...
(<span class="hljs-number">1</span>, <span class="hljs-string">'a'</span>) (<span class="hljs-number">2</span>, <span class="hljs-string">'b'</span>) (<span class="hljs-number">3</span>, <span class="hljs-string">'c'</span>)

cycle

cycle(iterable) 会把传入的一个序列无限重复下去,不过可以提供第二个参数就可以制定重复次数

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> cycle

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> zip(range(<span class="hljs-number">6</span>), cycle([<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>])):
<span class="hljs-prompt">... </span>    print(i, end=<span class="hljs-string">' '</span>)
...
(<span class="hljs-number">0</span>, <span class="hljs-string">'a'</span>) (<span class="hljs-number">1</span>, <span class="hljs-string">'b'</span>) (<span class="hljs-number">2</span>, <span class="hljs-string">'c'</span>) (<span class="hljs-number">3</span>, <span class="hljs-string">'a'</span>) (<span class="hljs-number">4</span>, <span class="hljs-string">'b'</span>) (<span class="hljs-number">5</span>, <span class="hljs-string">'c'</span>)

repeat

repeat(object[, times]) 返回一个元素无限重复下去的iterator,可以提供第二个参数就可以限定重复次数

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> repeat

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">for</span> i, s <span class="hljs-keyword">in</span> zip(count(<span class="hljs-number">1</span>), repeat(<span class="hljs-string">'over-and-over'</span>, <span class="hljs-number">5</span>)):
<span class="hljs-prompt">... </span>    print(i, s)
...
<span class="hljs-number">1</span> over-<span class="hljs-keyword">and</span>-over
<span class="hljs-number">2</span> over-<span class="hljs-keyword">and</span>-over
<span class="hljs-number">3</span> over-<span class="hljs-keyword">and</span>-over
<span class="hljs-number">4</span> over-<span class="hljs-keyword">and</span>-over
<span class="hljs-number">5</span> over-<span class="hljs-keyword">and</span>-over

Iterators terminating on the shortest input sequence

accumulate

accumulate(iterable[, func])

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> accumulate
<span class="hljs-prompt">>>> </span><span class="hljs-keyword">import</span> operator

<span class="hljs-prompt">>>> </span>list(accumulate([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>], operator.add))
[<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">6</span>, <span class="hljs-number">10</span>, <span class="hljs-number">15</span>]

<span class="hljs-prompt">>>> </span>list(accumulate([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>], operator.mul))
[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">6</span>, <span class="hljs-number">24</span>, <span class="hljs-number">120</span>]

chain

itertools.chain(*iterables)可以将多个iterable组合成一个iterator

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> chain

<span class="hljs-prompt">>>> </span>list(chain([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>], [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]))
[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]

chain的实现原理如下

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">chain</span><span class="hljs-params">(*iterables)</span>:</span>
    <span class="hljs-comment"># chain('ABC', 'DEF') --> A B C D E F</span>
    <span class="hljs-keyword">for</span> it <span class="hljs-keyword">in</span> iterables:
        <span class="hljs-keyword">for</span> element <span class="hljs-keyword">in</span> it:
            <span class="hljs-keyword">yield</span> element

chain.from_iterable

chain.from_iterable(iterable)和chain类似,但是只是接收单个iterable,然后将这个iterable中的元素组合成一个iterator

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> chain

<span class="hljs-prompt">>>> </span>list(chain.from_iterable([<span class="hljs-string">'ABC'</span>, <span class="hljs-string">'DEF'</span>]))
[<span class="hljs-string">'A'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-string">'C'</span>, <span class="hljs-string">'D'</span>, <span class="hljs-string">'E'</span>, <span class="hljs-string">'F'</span>]

实现原理也和chain类似

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">from_iterable</span><span class="hljs-params">(iterables)</span>:</span>
    <span class="hljs-comment"># chain.from_iterable(['ABC', 'DEF']) --> A B C D E F</span>
    <span class="hljs-keyword">for</span> it <span class="hljs-keyword">in</span> iterables:
        <span class="hljs-keyword">for</span> element <span class="hljs-keyword">in</span> it:
            <span class="hljs-keyword">yield</span> element

compress

compress(data, selectors)接收两个iterable作为参数,只返回selectors中对应的元素为True的data,当data/selectors之一用尽时停止

<span class="hljs-prompt">>>> </span>list(compress([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>], [<span class="hljs-keyword">True</span>, <span class="hljs-keyword">True</span>, <span class="hljs-keyword">False</span>, <span class="hljs-keyword">False</span>, <span class="hljs-keyword">True</span>]))
[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">5</span>]

zip_longest

zip_longest(*iterables, fillvalue=None)和zip类似,但是zip的缺陷是iterable中的某一个元素被遍历完,整个遍历都会停止,具体差异请看下面这个例子

<span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> zip_longest

r1 = range(<span class="hljs-number">3</span>)
r2 = range(<span class="hljs-number">2</span>)

print(<span class="hljs-string">'zip stops early:'</span>)
print(list(zip(r1, r2)))

r1 = range(<span class="hljs-number">3</span>)
r2 = range(<span class="hljs-number">2</span>)

print(<span class="hljs-string">'\nzip_longest processes all of the values:'</span>)
print(list(zip_longest(r1, r2)))

下面是输出结果

zip stops early:
[(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>), (<span class="hljs-number">1</span>, <span class="hljs-number">1</span>)]

zip_longest processes all of the values:
[(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>), (<span class="hljs-number">1</span>, <span class="hljs-number">1</span>), (<span class="hljs-number">2</span>, <span class="hljs-keyword">None</span>)]

islice

islice(iterable, stop) or islice(iterable, start, stop[, step]) 与Python的字符串和列表切片有一些类似,只是不能对start、start和step使用负值

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> islice

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> islice(range(<span class="hljs-number">100</span>), <span class="hljs-number">0</span>, <span class="hljs-number">100</span>, <span class="hljs-number">10</span>):
<span class="hljs-prompt">... </span>    print(i, end=<span class="hljs-string">' '</span>)
...
<span class="hljs-number">0</span> <span class="hljs-number">10</span> <span class="hljs-number">20</span> <span class="hljs-number">30</span> <span class="hljs-number">40</span> <span class="hljs-number">50</span> <span class="hljs-number">60</span> <span class="hljs-number">70</span> <span class="hljs-number">80</span> <span class="hljs-number">90</span>

tee

tee(iterable, n=2) 返回n个独立的iterator,n默认为2

<span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> islice, tee

r = islice(count(), <span class="hljs-number">5</span>)
i1, i2 = tee(r)

print(<span class="hljs-string">'i1:'</span>, list(i1))
print(<span class="hljs-string">'i2:'</span>, list(i2))

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> r:
    print(i, end=<span class="hljs-string">' '</span>)
    <span class="hljs-keyword">if</span> i > <span class="hljs-number">1</span>:
        <span class="hljs-keyword">break</span>

下面是输出结果,注意tee(r)后,r作为iterator已经失效,所以for循环没有输出值

i1: [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>]
i2: [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>]

starmap

starmap(func, iterable)假设iterable将返回一个元组流,并使用这些元组作为参数调用func:

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> starmap
<span class="hljs-prompt">>>> </span><span class="hljs-keyword">import</span> os

<span class="hljs-prompt">>>> </span>iterator = starmap(os.path.join,
<span class="hljs-prompt">... </span>                   [(<span class="hljs-string">'/bin'</span>, <span class="hljs-string">'python'</span>), (<span class="hljs-string">'/usr'</span>, <span class="hljs-string">'bin'</span>, <span class="hljs-string">'java'</span>),
<span class="hljs-prompt">... </span>                   (<span class="hljs-string">'/usr'</span>, <span class="hljs-string">'bin'</span>, <span class="hljs-string">'perl'</span>), (<span class="hljs-string">'/usr'</span>, <span class="hljs-string">'bin'</span>, <span class="hljs-string">'ruby'</span>)])

<span class="hljs-prompt">>>> </span>list(iterator)
[<span class="hljs-string">'/bin/python'</span>, <span class="hljs-string">'/usr/bin/java'</span>, <span class="hljs-string">'/usr/bin/perl'</span>, <span class="hljs-string">'/usr/bin/ruby'</span>]

filterfalse

filterfalse(predicate, iterable) 与filter()相反,返回所有predicate返回False的元素

itertools.filterfalse(is_even, itertools.count()) =>
<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-number">7</span>, <span class="hljs-number">9</span>, <span class="hljs-number">11</span>, <span class="hljs-number">13</span>, <span class="hljs-number">15</span>, ...

takewhile

takewhile(predicate, iterable) 只要predicate返回True,不停地返回iterable中的元素。一旦predicate返回False,iteration将结束

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">less_than_10</span><span class="hljs-params">(x)</span>:</span>
    <span class="hljs-keyword">return</span> x < <span class="hljs-number">10</span>

itertools.takewhile(less_than_10, itertools.count())
=> <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>

itertools.takewhile(is_even, itertools.count())
=> <span class="hljs-number">0</span>

dropwhile

dropwhile(predicate, iterable) 在predicate返回True时舍弃元素,然后返回其余迭代结果

itertools.dropwhile(less_than_10, itertools.count())
=> <span class="hljs-number">10</span>, <span class="hljs-number">11</span>, <span class="hljs-number">12</span>, <span class="hljs-number">13</span>, <span class="hljs-number">14</span>, <span class="hljs-number">15</span>, <span class="hljs-number">16</span>, <span class="hljs-number">17</span>, <span class="hljs-number">18</span>, <span class="hljs-number">19</span>, ...

itertools.dropwhile(is_even, itertools.count())
=> <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>, <span class="hljs-number">10</span>, ...

groupby

groupby(iterable, key=None) 把iterator中相邻的重复元素挑出来放在一起。p.s: The input sequence needs to be sorted on the key value in order for the groupings to work out as expected.

  • [k for k, g in groupby(‘AAAABBBCCDAABBB’)] –> A B C D A B
  • [list(g) for k, g in groupby(‘AAAABBBCCD’)] –> AAAA BBB CC D
<span class="hljs-prompt">>>> </span><span class="hljs-keyword">import</span> itertools

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">for</span> key, group <span class="hljs-keyword">in</span> itertools.groupby(<span class="hljs-string">'AAAABBBCCDAABBB'</span>):
<span class="hljs-prompt">... </span>    print(key, list(group))
...
A [<span class="hljs-string">'A'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-string">'A'</span>]
B [<span class="hljs-string">'B'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-string">'B'</span>]
C [<span class="hljs-string">'C'</span>, <span class="hljs-string">'C'</span>]
D [<span class="hljs-string">'D'</span>]
A [<span class="hljs-string">'A'</span>, <span class="hljs-string">'A'</span>]
B [<span class="hljs-string">'B'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-string">'B'</span>]
city_list = [(<span class="hljs-string">'Decatur'</span>, <span class="hljs-string">'AL'</span>), (<span class="hljs-string">'Huntsville'</span>, <span class="hljs-string">'AL'</span>), (<span class="hljs-string">'Selma'</span>, <span class="hljs-string">'AL'</span>),
             (<span class="hljs-string">'Anchorage'</span>, <span class="hljs-string">'AK'</span>), (<span class="hljs-string">'Nome'</span>, <span class="hljs-string">'AK'</span>),
             (<span class="hljs-string">'Flagstaff'</span>, <span class="hljs-string">'AZ'</span>), (<span class="hljs-string">'Phoenix'</span>, <span class="hljs-string">'AZ'</span>), (<span class="hljs-string">'Tucson'</span>, <span class="hljs-string">'AZ'</span>),
             ...
            ]

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_state</span><span class="hljs-params">(city_state)</span>:</span>
    <span class="hljs-keyword">return</span> city_state[<span class="hljs-number">1</span>]

itertools.groupby(city_list, get_state) =>
  (<span class="hljs-string">'AL'</span>, iterator-<span class="hljs-number">1</span>),
  (<span class="hljs-string">'AK'</span>, iterator-<span class="hljs-number">2</span>),
  (<span class="hljs-string">'AZ'</span>, iterator-<span class="hljs-number">3</span>), ...

iterator-<span class="hljs-number">1</span> =>  (<span class="hljs-string">'Decatur'</span>, <span class="hljs-string">'AL'</span>), (<span class="hljs-string">'Huntsville'</span>, <span class="hljs-string">'AL'</span>), (<span class="hljs-string">'Selma'</span>, <span class="hljs-string">'AL'</span>)
iterator-<span class="hljs-number">2</span> => (<span class="hljs-string">'Anchorage'</span>, <span class="hljs-string">'AK'</span>), (<span class="hljs-string">'Nome'</span>, <span class="hljs-string">'AK'</span>)
iterator-<span class="hljs-number">3</span> => (<span class="hljs-string">'Flagstaff'</span>, <span class="hljs-string">'AZ'</span>), (<span class="hljs-string">'Phoenix'</span>, <span class="hljs-string">'AZ'</span>), (<span class="hljs-string">'Tucson'</span>, <span class="hljs-string">'AZ'</span>)

Combinatoric generators

product

product(*iterables, repeat=1)

  • product(A, B) returns the same as ((x,y) for x in A for y in B)
  • product(A, repeat=4) means the same as product(A, A, A, A)
<span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> product


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show</span><span class="hljs-params">(iterable)</span>:</span>
    <span class="hljs-keyword">for</span> i, item <span class="hljs-keyword">in</span> enumerate(iterable, <span class="hljs-number">1</span>):
        print(item, end=<span class="hljs-string">' '</span>)
        <span class="hljs-keyword">if</span> (i % <span class="hljs-number">3</span>) == <span class="hljs-number">0</span>:
            print()
    print()


print(<span class="hljs-string">'Repeat 2:\n'</span>)
show(product(range(<span class="hljs-number">3</span>), repeat=<span class="hljs-number">2</span>))

print(<span class="hljs-string">'Repeat 3:\n'</span>)
show(product(range(<span class="hljs-number">3</span>), repeat=<span class="hljs-number">3</span>))
Repeat <span class="hljs-number">2</span>:

(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">0</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">0</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">1</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">1</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">2</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">2</span>, <span class="hljs-number">2</span>)

Repeat <span class="hljs-number">3</span>:

(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
(<span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>) (<span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>) (<span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>)

permutations

permutations(iterable, r=None)返回长度为r的所有可能的组合

<span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> permutations


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show</span><span class="hljs-params">(iterable)</span>:</span>
    first = <span class="hljs-keyword">None</span>
    <span class="hljs-keyword">for</span> i, item <span class="hljs-keyword">in</span> enumerate(iterable, <span class="hljs-number">1</span>):
        <span class="hljs-keyword">if</span> first != item[<span class="hljs-number">0</span>]:
            <span class="hljs-keyword">if</span> first <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">None</span>:
                print()
            first = item[<span class="hljs-number">0</span>]
        print(<span class="hljs-string">''</span>.join(item), end=<span class="hljs-string">' '</span>)
    print()


print(<span class="hljs-string">'All permutations:\n'</span>)
show(permutations(<span class="hljs-string">'abcd'</span>))

print(<span class="hljs-string">'\nPairs:\n'</span>)
show(permutations(<span class="hljs-string">'abcd'</span>, r=<span class="hljs-number">2</span>))

下面是输出结果

All permutations:

abcd abdc acbd acdb adbc adcb
bacd badc bcad bcda bdac bdca
cabd cadb cbad cbda cdab cdba
dabc dacb dbac dbca dcab dcba

Pairs:

ab ac ad
ba bc bd
ca cb cd
da db dc

combinations

combinations(iterable, r) 返回一个iterator,提供iterable中所有元素可能组合的r元组。每个元组中的元素保持与iterable返回的顺序相同。下面的实例中,不同于上面的permutations,a总是在bcd之前,b总是在cd之前,c总是在d之前

<span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> combinations


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show</span><span class="hljs-params">(iterable)</span>:</span>
    first = <span class="hljs-keyword">None</span>
    <span class="hljs-keyword">for</span> i, item <span class="hljs-keyword">in</span> enumerate(iterable, <span class="hljs-number">1</span>):
        <span class="hljs-keyword">if</span> first != item[<span class="hljs-number">0</span>]:
            <span class="hljs-keyword">if</span> first <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">None</span>:
                print()
            first = item[<span class="hljs-number">0</span>]
        print(<span class="hljs-string">''</span>.join(item), end=<span class="hljs-string">' '</span>)
    print()


print(<span class="hljs-string">'Unique pairs:\n'</span>)
show(combinations(<span class="hljs-string">'abcd'</span>, r=<span class="hljs-number">2</span>))

下面是输出结果

Unique pairs:

ab ac ad
bc bd
cd

combinations_with_replacement

combinations_with_replacement(iterable, r)函数放宽了一个不同的约束:元素可以在单个元组中重复,即可以出现aa/bb/cc/dd等组合

<span class="hljs-keyword">from</span> itertools <span class="hljs-keyword">import</span> combinations_with_replacement


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show</span><span class="hljs-params">(iterable)</span>:</span>
    first = <span class="hljs-keyword">None</span>
    <span class="hljs-keyword">for</span> i, item <span class="hljs-keyword">in</span> enumerate(iterable, <span class="hljs-number">1</span>):
        <span class="hljs-keyword">if</span> first != item[<span class="hljs-number">0</span>]:
            <span class="hljs-keyword">if</span> first <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">None</span>:
                print()
            first = item[<span class="hljs-number">0</span>]
        print(<span class="hljs-string">''</span>.join(item), end=<span class="hljs-string">' '</span>)
    print()


print(<span class="hljs-string">'Unique pairs:\n'</span>)
show(combinations_with_replacement(<span class="hljs-string">'abcd'</span>, r=<span class="hljs-number">2</span>))

下面是输出结果

aa ab ac ad
bb bc bd
cc cd
dd

operator的使用

attrgetter

operator.attrgetter(attr)和operator.attrgetter(*attrs)

  • After f = attrgetter(‘name’), the call f(b) returns b.name.
  • After f = attrgetter(‘name’, ‘date’), the call f(b) returns (b.name, b.date).
  • After f = attrgetter(‘name.first’, ‘name.last’), the call f(b) returns (b.name.first, b.name.last).

我们通过下面这个例子来了解一下itergetter的用法

<span class="hljs-prompt">>>> </span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span>:</span>
<span class="hljs-prompt">... </span>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, name, grade, age)</span>:</span>
<span class="hljs-prompt">... </span>        self.name = name
<span class="hljs-prompt">... </span>        self.grade = grade
<span class="hljs-prompt">... </span>        self.age = age
<span class="hljs-prompt">... </span>    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__repr__</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-prompt">... </span>        <span class="hljs-keyword">return</span> repr((self.name, self.grade, self.age))

<span class="hljs-prompt">>>> </span>student_objects = [
<span class="hljs-prompt">... </span>    Student(<span class="hljs-string">'john'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-number">15</span>),
<span class="hljs-prompt">... </span>    Student(<span class="hljs-string">'jane'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">12</span>),
<span class="hljs-prompt">... </span>    Student(<span class="hljs-string">'dave'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">10</span>),
<span class="hljs-prompt">... </span>]

<span class="hljs-prompt">>>> </span>sorted(student_objects, key=<span class="hljs-keyword">lambda</span> student: student.age)   <span class="hljs-comment"># 传统的lambda做法</span>
[(<span class="hljs-string">'dave'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">10</span>), (<span class="hljs-string">'jane'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">12</span>), (<span class="hljs-string">'john'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-number">15</span>)]

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> operator <span class="hljs-keyword">import</span> itemgetter, attrgetter

<span class="hljs-prompt">>>> </span>sorted(student_objects, key=attrgetter(<span class="hljs-string">'age'</span>))
[(<span class="hljs-string">'dave'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">10</span>), (<span class="hljs-string">'jane'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">12</span>), (<span class="hljs-string">'john'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-number">15</span>)]

<span class="hljs-comment"># 但是如果像下面这样接受双重比较,Python脆弱的lambda就不适用了</span>
<span class="hljs-prompt">>>> </span>sorted(student_objects, key=attrgetter(<span class="hljs-string">'grade'</span>, <span class="hljs-string">'age'</span>))
[(<span class="hljs-string">'john'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-number">15</span>), (<span class="hljs-string">'dave'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">10</span>), (<span class="hljs-string">'jane'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">12</span>)]

attrgetter的实现原理

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">attrgetter</span><span class="hljs-params">(*items)</span>:</span>
    <span class="hljs-keyword">if</span> any(<span class="hljs-keyword">not</span> isinstance(item, str) <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> items):
        <span class="hljs-keyword">raise</span> TypeError(<span class="hljs-string">'attribute name must be a string'</span>)
    <span class="hljs-keyword">if</span> len(items) == <span class="hljs-number">1</span>:
        attr = items[<span class="hljs-number">0</span>]
        <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">g</span><span class="hljs-params">(obj)</span>:</span>
            <span class="hljs-keyword">return</span> resolve_attr(obj, attr)
    <span class="hljs-keyword">else</span>:
        <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">g</span><span class="hljs-params">(obj)</span>:</span>
            <span class="hljs-keyword">return</span> tuple(resolve_attr(obj, attr) <span class="hljs-keyword">for</span> attr <span class="hljs-keyword">in</span> items)
    <span class="hljs-keyword">return</span> g

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">resolve_attr</span><span class="hljs-params">(obj, attr)</span>:</span>
    <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> attr.split(<span class="hljs-string">"."</span>):
        obj = getattr(obj, name)
    <span class="hljs-keyword">return</span> obj

itemgetter

operator.itemgetter(item)和operator.itemgetter(*items)

  • After f = itemgetter(2), the call f(r) returns r[2].
  • After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3]).

我们通过下面这个例子来了解一下itergetter的用法

<span class="hljs-prompt">>>> </span>student_tuples = [
<span class="hljs-prompt">... </span>    (<span class="hljs-string">'john'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-number">15</span>),
<span class="hljs-prompt">... </span>    (<span class="hljs-string">'jane'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">12</span>),
<span class="hljs-prompt">... </span>    (<span class="hljs-string">'dave'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">10</span>),
<span class="hljs-prompt">... </span>]

<span class="hljs-prompt">>>> </span>sorted(student_tuples, key=<span class="hljs-keyword">lambda</span> student: student[<span class="hljs-number">2</span>])   <span class="hljs-comment"># 传统的lambda做法</span>
[(<span class="hljs-string">'dave'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">10</span>), (<span class="hljs-string">'jane'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">12</span>), (<span class="hljs-string">'john'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-number">15</span>)]

<span class="hljs-prompt">>>> </span><span class="hljs-keyword">from</span> operator <span class="hljs-keyword">import</span> attrgetter

<span class="hljs-prompt">>>> </span>sorted(student_tuples, key=itemgetter(<span class="hljs-number">2</span>))
[(<span class="hljs-string">'dave'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">10</span>), (<span class="hljs-string">'jane'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">12</span>), (<span class="hljs-string">'john'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-number">15</span>)]

<span class="hljs-comment"># 但是如果像下面这样接受双重比较,Python脆弱的lambda就不适用了</span>
<span class="hljs-prompt">>>> </span>sorted(student_tuples, key=itemgetter(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>))
[(<span class="hljs-string">'john'</span>, <span class="hljs-string">'A'</span>, <span class="hljs-number">15</span>), (<span class="hljs-string">'dave'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">10</span>), (<span class="hljs-string">'jane'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-number">12</span>)]

itemgetter的实现原理

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">itemgetter</span><span class="hljs-params">(*items)</span>:</span>
    <span class="hljs-keyword">if</span> len(items) == <span class="hljs-number">1</span>:
        item = items[<span class="hljs-number">0</span>]
        <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">g</span><span class="hljs-params">(obj)</span>:</span>
            <span class="hljs-keyword">return</span> obj[item]
    <span class="hljs-keyword">else</span>:
        <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">g</span><span class="hljs-params">(obj)</span>:</span>
            <span class="hljs-keyword">return</span> tuple(obj[item] <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> items)
    <span class="hljs-keyword">return</span> g

methodcaller

operator.methodcaller(name[, args…])

  • After f = methodcaller(‘name’), the call f(b) returns b.name().
  • After f = methodcaller(‘name’, ‘foo’, bar=1), the call f(b) returns b.name(‘foo’, bar=1).

methodcaller的实现原理

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">methodcaller</span><span class="hljs-params">(name, *args, **kwargs)</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">caller</span><span class="hljs-params">(obj)</span>:</span>
        <span class="hljs-keyword">return</span> getattr(obj, name)(*args, **kwargs)
    <span class="hljs-keyword">return</span> caller

References

转载自http://www.ziwenxie.site/2017/01/15/python-functools-itertools-operator/

admin
版权声明:本站原创文章,由admin2017-01-19发表,共计12768字。
转载提示:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)