Python函数式编程模块总结——functools与itertools

前言

函数式编程模块和容器模块是Python标准库中比较经典和实用的模块。尝试着在编码中用上这些模块,将会大大简化代码,使你变得更加pythonic。

functools——高阶函数和可调用对象上的操作

lru_cache(maxsize=128, typed=False)

功能

​ 为函数提供缓存功能的装饰器,当函数返回结果相同时就返回缓存的结果。

参数

  • maxsize: 缓存次数上限,设为None无上限,大小最好设为2的幂。
  • typed:缓存方式,设为true,函数参数位置或者类型不同也会触发缓存,即使参数意义相同、结果相同。

实例方法

  • cache_info(): 查看缓存信息
  • cache_clean(): 清除缓存

使用场景

​ 函数经常被重复调用且返回结果基本上很少变化,例如斐波那契递归调用,访问静态Web内容调用等。

demo

  • 缓存静态网页内容:

    使用方式代码,这里设置最大缓存次数为32次:

    import urllib.request, urllib.error
    
    @lru_cache(maxsize=32)
    def get_pep(num):
        resource = 'http://www.python.org/dev/peps/pep-%04d/' % num
        try:
            with urllib.request.urlopen(resource) as s:
                return s.read()
        except urllib.error.HTTPError:
            return 'Not Found!'
    
    if __name__ == "__main__":
        for n in 8, 290, 308, 320:
            pep = get_pep(n)
            print(n, len(pep))
            
    # 打印结果
    8 107260
    290 60021
    308 57227
    320 49806
    
  • 缓存斐波那契递归结果:

    函数运行计时装饰器:

    import time 
    import functools
    
    def clock(func):
        """函数运行计时装饰器"""
        @functools.wraps(func)
        def clocked(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            spend_time = time.time() - start_time
            func_name = func.__name__
            arg_list = []
            if args:
                arg_list.append(', '.join(repr(arg) for arg in args))
            if kwargs:
                pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
                arg_list.append(', '.join(pairs))
            arg_str = ', '.join(arg_list)
            print(f'[{spend_time:0.8f}] {func_name}({arg_str}) -> {result}')
    
            return result
        return clocked
    

    不使用缓存的递归:

    @clock
    def fib(n):
        if n < 2:
            return n
        return fib(n-1) + fib(n-2)
    

    结果,发现相同的参数计算了很多次:

    [0.00000000] fib(1) -> 1
    [0.00000000] fib(0) -> 0
    [0.00000000] fib(2) -> 1
    [0.00000000] fib(1) -> 1
    [0.00000000] fib(3) -> 2
    [0.00000000] fib(1) -> 1
    [0.00000000] fib(0) -> 0
    [0.00000000] fib(2) -> 1
    [0.00099897] fib(4) -> 3
    [0.00000000] fib(1) -> 1
    [0.00000000] fib(0) -> 0
    [0.00000000] fib(2) -> 1
    [0.00000000] fib(1) -> 1
    [0.00000000] fib(3) -> 2
    [0.00099897] fib(5) -> 5
    [0.00000000] fib(1) -> 1
    [0.00000000] fib(0) -> 0
    [0.00099993] fib(2) -> 1
    [0.00000000] fib(1) -> 1
    [0.00299740] fib(3) -> 2
    [0.00000000] fib(1) -> 1
    [0.00000000] fib(0) -> 0
    [0.00099921] fib(2) -> 1
    [0.00399661] fib(4) -> 3
    [0.00499558] fib(6) -> 8
    8
    

    使用缓存,只计算参数不同的,花费时间也少:

    [0.00000000] fib(1) -> 1
    [0.00000000] fib(0) -> 0
    [0.00799775] fib(2) -> 1
    [0.00799775] fib(3) -> 2
    [0.00799775] fib(4) -> 3
    [0.00799775] fib(5) -> 5
    [0.00899482] fib(6) -> 8
    8
    

    查看缓存信息,清理缓存后在查看下缓存信息:

        print(fib.cache_info())
        print(fib.cache_clear())
        print(fib.cache_info())
        
    #结果##########################
    	CacheInfo(hits=4, misses=7, maxsize=None, currsize=7)
    	None
    	CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)
    

total_ordering

功能

  • 自动补全自定义类内置比较运算符方法。

使用场景

  • 自定义类需要重载运算符的时候,不用将所需要的内置方法都实现,只用实现需要重载的那个运算符方法就可以了。

demo

@functools.total_ordering
class Name:
    def __init__(self):
        self.age = 0
        self.first_name = ''
        self.last_name = ''

    def __eq__(self, other):
        print('===没有使用到装饰器===')
        return self.age == other.age

    def __gt__(self, other):
        print('装饰器自动补全比较运算符')
        return self.age > other.age


if __name__ == "__main__":
    a = Name()
    b = Name()

    a.first_name = '周'
    a.last_name = '杰伦'
    a.age = 40

    b.first_name = '章'
    b.last_name = '子怡'
    b.age = 18

    print(a == b)
    print(a >= b)
    print(a <= b)
    print(a < b)

##结果##########################################
===没有使用到装饰器===
False
装饰器自动补全比较运算符
True
装饰器自动补全比较运算符
False
装饰器自动补全比较运算符
False

##将装饰器注释掉的结果############################
===没有使用到装饰器会报错===
False
Traceback (most recent call last):
  File "c:/Users/Administrator/Desktop/a.py", line 34, in <module>
    print(a >= b)
TypeError: '>=' not supported between instances of 'Name' and 'Name'

partial(func, *args, **keywords)

功能

  • 将原函数进一步封装,冻结一部分参数(也就是将一部分参数写死封装),返回一个新的签名对象,该对象只要给部分参数赋值就可以了。

参数说明

  • func: 需要封装的函数名
  • *args: func的可变参数
  • **keywwords: func的关键字参数

使用场景

  • 当原函数参数过多,每次使用传参都只需要传递部分参数的值,其他参数默认,这种情况下就可以使用partial装饰。
  • 对接口进一步分装,当调用接口不想暴露太多,可以使用该装饰器进行封装。

demo

import functools

def add(a, b):
    return a + b

# 冻结参数a
>>> plus = functools.partial(add, 3)
>>> plus(4) 
7

# 当对所有参数都进行了封装的话那么在调用的时候就不能在传递参数了,否则会报错
>>> plus = functools.partial(add, 3, 4) 
>>> plus()
7
>>> plus(5) 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: add() takes 2 positional arguments but 3 were given
>>>
import functools

# 带默认值的函数
def add(a, b, c=2):
    return a + b + c
    
>>> plus = functools.partial(add, b=1) 
>>> plus(3)                           
6
>>>
import functools

# 不限制参数
def add(*args, **kwargs):
    return functools.reduce(lambda x,y: x+y, args)
import functools

def add(*args, **kwargs):
    return functools.reduce(lambda x,y: x+y, args)
>>> plus = functools.partial(add, 1, 2) 
>>> plus(3) 
6
>>> plus(c=12) 
3

partialmethod(func, *args, **kwargs)

功能

  • 和partial相似,都是返回一个新的签名的对象,但是该装饰器装饰的是类中的方法。

参数说明

  • func: 类中的方法名。

demo

import functools

class Cell:
    def __init__(self):
        self._alive = False

    @property
    def alive(self):
        return self._alive

    def set_state(self, state):
        self._alive = bool(state)

    set_alive = functools.partialmethod(set_state, True)
    set_dead = functools.partialmethod(set_state, False)

>>> c = Cell()
>>> c.alive
False
>>> c.set_alive()
>>> c.alive
True

reduce(func, iterable[, initializer])

功能

  • 将可迭代对象中的元素累计应用到对应的func中。

参数说明

  • func: 累计应用的规则函数,一般为lambda函数。
  • initialier: 初始值的默认值,可选参数。

使用场景

  • 需要对可迭代对象中的每一个元素进行累积操作时。

demo

>>> functools.reduce(lambda x, y: x+y, [1, 2, 3, 4])
10 
>>> functools.reduce(lambda x, y: x+y, [1, 2, 3, 4], 10)            
20

singledispatch

功能

  • 将普通函数转换为泛型函数的工具。
    • 泛型函数:指由多个函数组成的函数,可以对不同类型实现相同的操作,调用时应该使用哪个实现由分派算法决定。
    • Single dispatch: 一种泛型函数分派形式,基于单个参数的类型决定(函数的第一个参数)。

使用场景

  • 一般在设计模式用使用的较多,更具参数类型来决定调用哪个函数或者方法。

demo


>>> from functools import singledispatch
>>> 
>>> @singledispatch
... def fun(arg, verbose=False):
...     if verbose:
...             print("Let me just say,", end=" ") 
...     print(arg) 
... 
>>> # 将要重载的函数使用register()装饰
... 
>>> @fun.register
... def _(arg: int, verbose=False):
...     if verbose:
...             print("Strength in numbers, eh?", end=" ")   
...     print(arg) 
... 
>>> @fun.register
... def _(arg:list, verbose=False):
...     if verbose:
...             print("Enumerate this:")
...     for i, elem in enumerate(arg):
...             print(i, elem) 
... 
>>> @fun.register(complex)
... def _(arg, verbose=False):
...     if verbose:
...             print("Better than complicated.", end=" ")
...     print(arg.real, arg.imag)  
... 
>>> # 要启用注册lambda和现有函数,可以使用函数形式的register()属性
... def nothing(arg, verbose=False):
...     print("Nothing.") 
... 
>>> fun.register(type(None), nothing) 
<function nothing at 0x000001A9135A2378>
>>> # 转发参数类型为字符串的函数
... fun("Hello, world.") 
Hello, world.
>>> # 转发参数类型为int类型的函数
... fun(10, verbose=True) 
Strength in numbers, eh? 10
>>> # 转发参数类型为列表的函数
... fun(['spam', 'spam', 'eggs', 'spam'], verbose=True) 
Enumerate this:
0 spam
1 spam
2 eggs
3 spam
>>> # 转发现有函数       
... fun(None) 
Nothing.
>>> # 转发参数类型为复数的函数
>>> fun(123-12j) 
123.0 -12.0
>>>

singledispatch用于函数,方法需要使用singledispatchmethod(python3.8版本以上)。

wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

功能

  • 自定义装饰器时,装饰器返回的对象保留原有对象的属性(__module__, __name__, __qualname__, __annotations____doc__)

参数

  • wrapped: 被装饰函数对象。
  • WRAPPER_ASSIGNMENTS :被装饰函数的(__module__, __name__, __qualname__, __annotations____doc__)
  • WRAPPER_UPDATES: 被装饰函数的__dict__

使用场景

  • 当函数被多个装饰器装饰时,装饰器必须使用该装饰器装饰,否则会报错。
  • 希望函数被装饰后,保留原有的属性。

demo

from functools import wraps

def my_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        print("Calling decorated function")
        return f(*args, **kwargs)
    return wrapper

@my_decorator
def example():
    """Docstring"""
    print("Called example function")

if __name__ == "__main__":
    example()
    print(example.__name__)
    print(example.__doc__)
    print(example.__qualname__)
    print(example.__module__)
Calling decorated function
Called example function
example
Docstring
example
__main__

itertools —— 为高效循环而创建迭代器的函数

无穷迭代器

迭代器实参结果示例
count()start, [step]start, start+step, start+2*step, …count(10) --> 10 11 12 13 14 ...
cycle()pp0, p1, … plast, p0, p1, …cycle('ABCD') --> A B C D A B C D ...
repeat()elem [,n]elem, elem, elem, … 重复无限次或n次repeat(10, 3) --> 10 10 10
  • count(start=0, step=1)

    从start开始,每次增加step:

    from itertools import *
    
    for i in count(10, 2):
        print(i)
        if i > 20:
            break
    
    ########结果打印#########
    10
    12
    14
    16
    18
    20
    22
    

    使用场景

    • map()结合生成连续的数据点。

      for x in map(lambda x, y: x * y, [10, 20, 30], itertools.count(1)):
          print(x)
      
      #####结果######
      10
      40
      90
      
    • 与zip结合,为zip添加序列号:

      fruits_list = ["apple", "peer", "banana"]
      count_list = ["2", "3", "10"]
      
      
      for i in zip(itertools.count(start=1, step=1), fruits_list, count_list):
          print(i)
      
      ###结果###
      (1, 'apple', '2')
      (2, 'peer', '3')
      (3, 'banana', '10')
      
  • cycle(iterable)

    无线循环可迭代对象。

    cnt = itertools.count(1, 1)
    
    for i in itertools.cycle('ABCD'):
        print(i, end=f'第{cnt}行\r\n')
        if next(cnt) == 10:
            break
    
    ###结果####
    A第count(1)行
    B第count(2)行
    C第count(3)行
    D第count(4)行
    A第count(5)行
    B第count(6)行
    C第count(7)行
    D第count(8)行
    A第count(9)行
    B第count(10)行
    
  • repeat(object[,times])

    不断重复object, times可选择重复次数。

    使用场景

    • 在map或者zip中提供一个常量流(就是无限循环的常量):

      >>> list(map(pow, range(10), itertools.repeat(2))) 
      [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
      
      >>> list(zip(range(10), itertools.repeat('A'))) 
      [(0, 'A'), (1, 'A'), (2, 'A'), (3, 'A'), (4, 'A'), (5, 'A'), (6, 'A'), (7, 'A'), (8, 'A'), (9, 'A')]
      

根据规则过滤迭代器

  • accumulate(iterable[, func])

    将可迭代对象每个位置不断与前边的值累计计算,根据func定累计规则,默认为累加,返回一个每个位置累计后的迭代器。

    使用场景

    当需要累计计算并且需要知道每个位置的值时。

    >>> from itertools import accumulate
    >>> import operator
    >>> 
    >>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]
    >>> list(accumulate(data))               
    [3, 7, 13, 15, 16, 25, 25, 32, 37, 45]
    >>> # 累计想乘
    ... list(accumulate(data, operator.mul)) 
    [3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]
    >>> # 自定义lambda累计规则
    ... cashflows =[1000, -90, -90, -90, -90] 
    >>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt)) 
    [1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001]
    >>> # 如果设置func为max, 则将遇到的最大值后边的比它小的值都设为最大值得值,
    ... # 直到遇到一个比最大值更大的值,继续重复前边的操作。
    ... list(accumulate(data, max)) 
    [3, 4, 6, 6, 6, 9, 9, 9, 9, 9]
    >>> # 设置func为min则和max相反,将比它大的值都设为最小值
    ... #  直到遇到比它更小的值,重复前边的操作。
    ... list(accumulate(data, min)) 
    [3, 3, 3, 2, 1, 1, 0, 0, 0, 0]
    
  • compress(data, selectors)
    创建一个迭代器,返回data中经selectors真值测试为True的元素。迭代器在两者较短的长度处停止。

    使用场景

    根据一个可迭代对象过滤另一个可迭代对象,返回对应位置为true的元素。

    >>> from itertools import compress 
    >>> list(compress('ABCDEF', [1, 0, 1, 0])) 
    ['A', 'C']
    
  • filterfalse(predicate, iterable)

    创建一个迭代器,返回iterable中predicate为False的元素。如果predicate是None, 返回真值测试为false的元素。

    使用场景

    返回可迭代对象不符合规则的元素,当规则默认为None时,返回bool为false的元素。

    >>> from itertools import filterfalse
    >>> list(filterfalse(lambda x: x%2, range(10)))
    [0, 2, 4, 6, 8]
    >>> list(filterfalse(None, [1, 0, -1, 2])) 
    [0]
    
  • dropwhile(predicate, iterable)

    创建一个迭代器,根据规则从左到右迭代可迭代对象,结果为true继续迭代,结果为false时停止规则校验,迭代返回该值及后续所有值。

    使用场景

    可迭代对象不符合规则时,返回后续所有值。

    >>> from itertools import dropwhile
    >>> list(dropwhile(lambda x: x<5, [1, 2, 3, 6, 4, 2])) 
    [6, 4, 2]
    >>> list(dropwhile(lambda x: x<5, [6, 2, 3, 6, 4, 2])) 
    [6, 2, 3, 6, 4, 2]
    
  • takewhile(predicate, iterable)

    创建一个迭代器, 只要predicate为真就从可迭代对象中返回元素,当遇到假时,停止迭代。

    使用场景

    依次返回可迭代对象中符合规则的元素,当不符合规则时,停止迭代。

    >>> from itertools import takewhile
    >>> list(takewhile(lambda x: x<5, [1, 2, 5, 2, 1]))
    [1, 2]
    >>> list(takewhile(lambda x: x<5, [5, 1, 2, 5, 2, 1])) 
    [] 
    

根据规则合并迭代器

  • chain(*iterables)

    创建一个迭代器,将多个可迭代对象合并为单个序列。

    使用场景

    需要将多个可迭代对象合并时。

    >>> from itertools import chain
    >>> list(chain('ABC', 'DEF'))
    ['A', 'B', 'C', 'D', 'E', 'F']
    >>> list(chain([{'a':1, 'b':2}, 'aaa', (1, 2), {3, 4}], 'ADC')) 
    [{'a': 1, 'b': 2}, 'aaa', (1, 2), {3, 4}, 'A', 'D', 'C']
    
  • chain.from_iterable(iterable)

    和chain类似,不过参数是一个可迭代对象, 将该可迭代对象中的每一个元素当做一个可迭代对象进行合并为单个序列。

    使用场景

    需要将一个可迭代对象中的所有元素依次迭代。

    >>> list(chain.from_iterable(['ABC', 'DEF', (1,2)])) 
    ['A', 'B', 'C', 'D', 'E', 'F', 1, 2]
    
  • zip_longest(*iterables, fillvalue=None)

    zip的升级版,可以将不同长度的可迭代对象合并,使用fillvalue内容填充较短的可迭代对象对应的位置。

    使用场景

    对应合并多个不同长度的可迭代对象为元组。

    >>> from itertools import zip_longest
    >>> list(zip_longest('ABCD', 'abc')) 
    [('A', 'a'), ('B', 'b'), ('C', 'c'), ('D', None)]
    >>> list(zip_longest('ABCD', 'abc', fillvalue='*')) 
    [('A', 'a'), ('B', 'b'), ('C', 'c'), ('D', '*')]
    

拆分截取迭代器

  • islice(iterable, start, stop[, step])

    迭代器切片,和切片的效果一样,但是该方法可以读取并截取文档内容并返回迭代对象。

    使用场景

    在读取大数据量文档内容,但是只需要读取其中少量内容使用迭代器切片比使用readlines速度更快,效率更高。

    my_file.txt

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #  
    #  Copyright 2019 wzg16 <wzg16@wzg16-linux>
    #  
    #  This program is free software; you can redistribute it and/or modify
    #  it under the terms of the GNU General Public License as published by
    #  the Free Software Foundation; either version 2 of the License, or
    #  (at your option) any later version.
    #  
    #  This program is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #  
    #  You should have received a copy of the GNU General Public License
    #  along with this program; if not, write to the Free Software
    #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
    #  MA 02110-1301, USA.
    

    读取文档前三行:

    ##使用readlines方法
     
    with open("my_file.txt") as f:
    	lines = f.readlines()
    	print(lines[0:3])
     
    """
    返回:
    ['#!/usr/bin/env python\n', '# -*- coding: utf-8 -*-\n', '#\n']
    """
    
    ##使用迭代器切片方法
    from itertools import islice
     
    with open("my_files.txt") as f2:
    	for i in islice(f2,0,3):
    		print(i)
    	result = islice(f2,0,3)
    	print(result)
    	print(list(result))
     
    """
    输出:
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #  
    <itertools.islice object at 0x7f52a94dedb8>
    ['#  Copyright 2019 wzg16 <wzg16@wzg16-linux>\n', '#  \n', '#  This program is free software; you can redistribute it and/or modify\n']
    """
    
  • tee(iterable, n=2)

    将一个可迭代对象拆分为多个独立的迭代器, n指定拆分数量。

    >>> my_list = [1, 2, 3, 4]     
    >>> iter_tee = tee(my_list, 3)
    >>> for iter in iter_tee:
    ...     print(iter)
    ...     print([x for x in iter]) 
    ... 
    <itertools._tee object at 0x000001B97AAF3FC8>
    [1, 2, 3, 4]
    <itertools._tee object at 0x000001B97AAFA208>
    [1, 2, 3, 4]
    <itertools._tee object at 0x000001B97AAFA248>
    [1, 2, 3, 4]
    
    
    ###################
    被拆分的可迭代对象不应该再被使用,否则tee对象无法得知iterable可能已向后迭代
    ###################
    >>> my_list.append(5) 
    >>> for iter in iter_tee:
    ...     print(iter)       
    ...     print([x for x in iter])
    ... 
    <itertools._tee object at 0x000001B97AAF3FC8>
    []
    <itertools._tee object at 0x000001B97AAFA208>
    []
    <itertools._tee object at 0x000001B97AAFA248>
    []
    >>> 
    
    ##################
    不要在多线程中使用被拆分后的同一个迭代器对象
    ##################
    from itertools import tee
    import threading
    
    def get_tee(list_name):
       return tee(list_name, 3)[0]
    
    def change_iter(iter_name):
        my_list = [_ for _ in iter_name]
        print(f'线程1中迭代器内容:{my_list}')
    
    def change_iter2(iter_name):
        my_list = [_ for _ in iter_name]
        print(f'线程2中迭代器内容:{my_list}')
        
    
    def main():
        my_list = [1, 2, 3, 4]
        iter_name = get_tee(my_list)
        thread1 = threading.Thread(target=change_iter, args=(iter_name,))
        thread2 = threading.Thread(target=change_iter2, args=(iter_name,))
    
        thread1.start()
        thread2.start()
    
    
    
    if __name__ == "__main__":
        main()
    
    #####结果#####
    线程1中迭代器内容:[1, 2, 3, 4]
    线程2中迭代器内容:[]
    #############
    

分组迭代器

  • groupby(iterable, key=None)

    将相邻的重复元素跳出来放在一起。

    使用场景

    根据key对可迭代对象进行分组,返回分组后的迭代器。

    from itertools import groupby
    
    data = [
        ("1班", "刘一", 93),
        ("1班", "刘二", 93),
        ("1班", "刘三", 93),
        ("2班", "张一", 93),
        ("2班", "张二", 93),
        ("2班", "张三", 93),
        ("3班", "李一", 93),
        ("3班", "李二", 93),
        ("3班", "李三", 93),
    ]
    
    for key, group in groupby(data, key=lambda m: m[0]):
        print(key, list(group))
    

映射迭代器

  • starmap(function, iterable)

    和map作用一样,不过iterable为组合好的元祖构成的可迭代对象。当参数对应的形参已从一个单独可迭代对象组合为元组时(数据已被“预组对”)可用此函数代替 map。

    使用场景

    当参数对应形参已构成元组对时,可以使用此映射。

    >>> list(starmap(pow, [(2,5), (3,2), (10,3)]))
    [32, 9, 1000]
    

排列组合迭代器

  • product(*iterables, repeat=1)

    可迭代对象输入的笛卡尔积。repeat设置重复次数。

    >>> list(product('ABCD', 'XY'))
    [('A', 'X'), ('A', 'Y'), ('B', 'X'), ('B', 'Y'), ('C', 'X'), ('C', 'Y'), ('D', 'X'), ('D', 'Y')]
    
    >>> list(product('ABCD', 'XY', repeat=2)) 
    # 相当于list(product('ABCD', 'XY', 'ABCD', 'XY')) 
    
    [('A', 'X', 'A', 'X'), ('A', 'X', 'A', 'Y'), ('A', 'X', 'B', 'X'), ('A', 'X', 'B', 'Y'), ('A', 'X', 'C', 'X'), ('A', 'X', 'C', 'Y'), ('A', 'X', 'D', 'X'), ('A', 'X', 'D', 'Y'), ('A', 'Y', 'A', 'X'), ('A', 'Y', 'A', 'Y'), ('A', 'Y', 'B', 'X'), ('A', 'Y', 'B', 'Y'), ('A', 'Y', 'C', 'X'), ('A', 'Y', 'C', 'Y'), ('A', 'Y', 'D', 'X'), ('A', 'Y', 'D', 'Y'), ('B', 'X', 'A', 'X'), ('B', 'X', 'A', 'Y'), ('B', 'X', 'B', 'X'), ('B', 'X', 'B', 'Y'), ('B', 'X', 'C', 'X'), ('B', 'X', 'C', 'Y'), ('B', 'X', 'D', 'X'), ('B', 'X', 'D', 'Y'), ('B', 'Y', 
    'A', 'X'), ('B', 'Y', 'A', 'Y'), ('B', 'Y', 'B', 'X'), ('B', 'Y', 'B', 'Y'), ('B', 'Y', 'C', 'X'), ('B', 'Y', 'C', 'Y'), ('B', 'Y', 'D', 'X'), ('B', 'Y', 'D', 'Y'), ('C', 'X', 'A', 'X'), ('C', 'X', 'A', 'Y'), ('C', 'X', 'B', 'X'), ('C', 'X', 'B', 'Y'), ('C', 'X', 'C', 'X'), ('C', 'X', 'C', 'Y'), ('C', 'X', 'D', 'X'), ('C', 'X', 'D', 'Y'), ('C', 'Y', 'A', 'X'), ('C', 'Y', 'A', 'Y'), ('C', 'Y', 'B', 'X'), ('C', 'Y', 'B', 'Y'), ('C', 'Y', 'C', 'X'), ('C', 'Y', 'C', 'Y'), ('C', 'Y', 'D', 'X'), ('C', 'Y', 'D', 'Y'), ('D', 'X', 'A', 'X'), ('D', 'X', 'A', 'Y'), ('D', 'X', 'B', 'X'), ('D', 'X', 'B', 'Y'), ('D', 'X', 'C', 'X'), ('D', 'X', 'C', 'Y'), ('D', 'X', 'D', 'X'), ('D', 'X', 'D', 'Y'), ('D', 'Y', 'A', 'X'), ('D', 'Y', 'A', 'Y'), ('D', 'Y', 'B', 'X'), ('D', 'Y', 'B', 'Y'), ('D', 'Y', 'C', 'X'), ('D', 'Y', 'C', 'Y'), ('D', 'Y', 'D', 'X'), ('D', 'Y', 'D', 'Y')]
    >>>
    
  • permutations(iterable, r=None)

    返回由可迭代对象元素生成长度为r的排列,无重复元素。r默认为iterable的长度。

    如果可迭代对象是有序的,生成的排列也是有序的。

    排列中相同元素在不同位置也被视为不同排列,如AB、BA被视为不同排列。

    >>> list(permutations('ABCD', 2)) 
    [('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'A'), ('B', 'C'), ('B', 'D'), ('C', 'A'), ('C', 'B'), ('C', 'D'), ('D', 'A'), ('D', 'B'), ('D', 'C')]
    >>> list(permutations(range(3)))  
    [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
    >>>
    
  • combinations(iterable, r)

    返回由可迭代对象元素组成长度为r的子序列(如BA不是ABCD的子序列,这是和permutations的区别),无重复元素。

    如果可迭代对象是有序的,生成的组合也是有序的。

    >>> list(combinations('ABCD', 2)) 
    [('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
    
  • combinations_with_replacement(iterable, r)

    返回由输入iterable中元素组成的长度为r的子序列(和combinations比多了可以元素可以重复),允许每个元素可重复出现。

    如果可迭代对象是有序的,生成的组合也是有序的。

    >>> list(combinations_with_replacement('ABCD', 2)) 
    [('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'B'), ('B', 'C'), ('B', 'D'), ('C', 'C'), ('C', 'D'), ('D', 'D')]
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一切如来心秘密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值