前言
函数式编程模块和容器模块是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() | p | p0, 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')]