教程和理解工具¶
列表解析¶
列表解析 是在Python中构造列表的一种非常方便的方法。您可以使用以下任一习惯用法:
[ <expr> for <name> in <iterable> ]
[ <expr> for <name> in <iterable> if <condition> ]
例如,下面是一些方块的列表:
sage: [ i^2 for i in [1, 3, 7] ]
[1, 9, 49]
sage: [ i^2 for i in range(1,10) ]
[1, 4, 9, 16, 25, 36, 49, 64, 81]
sage: [ i^2 for i in range(1,10) if i % 2 == 1]
[1, 9, 25, 49, 81]
后者的变体是:
sage: [i^2 if i % 2 == 1 else 2 for i in range(10)]
[2, 1, 2, 9, 2, 25, 2, 49, 2, 81]
Exercises
构造1到10之间的素数整数的平方的列表:
sage: # edit here
构造一个小于100的完美正方形列表(提示:使用
srange()
使用该方法获取Sage整数的列表i.sqrtrem()
):sage: # edit here
在列表理解中可以使用多个iterable::
sage: [ (i,j) for i in range(1,6) for j in range(1,i) ]
[(2, 1), (3, 1), (3, 2), (4, 1), (4, 2), (4, 3), (5, 1), (5, 2), (5, 3), (5, 4)]
警告
注意前面表达式中嵌套循环的顺序。
如果要构建列表列表,则可以使用嵌套列表,如:
sage: [ [ binomial(n, i) for i in range(n+1) ] for n in range(10) ]
[[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
[1, 4, 6, 4, 1],
[1, 5, 10, 10, 5, 1],
[1, 6, 15, 20, 15, 6, 1],
[1, 7, 21, 35, 35, 21, 7, 1],
[1, 8, 28, 56, 70, 56, 28, 8, 1],
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]]
Exercises
计算对列表 (i,j) 非负整数的
i
至多 5 ,j
至多8
和i
和j
共同质素:sage: # edit here
计算相同的列表 i < j < 10 ::
sage: # edit here
遍历器¶
定义¶
为了构建理解,Python实际上使用 迭代器 . 这是一个运行于一堆对象中的设备,每次调用 next
方法。迭代器是用括号生成的:
sage: it = (binomial(8, i) for i in range(9))
sage: next(it)
1
sage: next(it)
8
sage: next(it)
28
sage: next(it)
56
您可以得到尚未得到的结果列表 消耗 ::
sage: list(it)
[70, 56, 28, 8, 1]
要求更多元素会触发 StopIteration
例外:
sage: next(it)
Traceback (most recent call last):
...
StopIteration
迭代器可以用作函数的参数。以下两个习惯用法给出了相同的结果;但是,第二个习惯用法(对于大型示例)更节省内存,因为它不扩展内存中的任何列表:
sage: sum([binomial(8, i) for i in range(9)])
256
sage: sum(binomial(8, i) for i in xrange(9)) # py2
256
sage: sum(binomial(8, i) for i in range(9)) # py3
256
Exercises
计算 binom{{10}}{{i}} 即使如此 i ::
sage: # edit here
求所有副素数的乘积之和 i, j 对于 i<j<10 ::
sage: # edit here
迭代器的典型用法¶
迭代器对函数非常方便 all()
, any()
和 exists()
::
sage: all([True, True, True, True])
True
sage: all([True, False, True, True])
False
sage: any([False, False, False, False])
False
sage: any([False, False, True, False])
True
让我们检查所有大于2的质数都是奇数:
sage: all( is_odd(p) for p in range(1,100) if is_prime(p) and p>2 )
True
众所周知,如果 2^p-1
那是最好的 p
是质数:
sage: def mersenne(p): return 2^p -1
sage: [ is_prime(p) for p in range(20) if is_prime(mersenne(p)) ]
[True, True, True, True, True, True, True]
反之亦然:
sage: all( is_prime(mersenne(p)) for p in range(1000) if is_prime(p) )
False
在这里使用列表要慢得多:
sage: %time all( is_prime(mersenne(p)) for p in range(1000) if is_prime(p) ) # not tested
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.00 s
False
sage: %time all( [ is_prime(mersenne(p)) for p in range(1000) if is_prime(p)] ) # not tested
CPU times: user 0.72 s, sys: 0.00 s, total: 0.73 s
Wall time: 0.73 s
False
你可以用 exists()
. 它有两个参数:一个迭代器和一个测试应该包含的属性的函数:
sage: exists( (p for p in range(1000) if is_prime(p)), lambda p: not is_prime(mersenne(p)) )
(True, 11)
另一种方法是:
sage: counter_examples = (p for p in range(1000) if is_prime(p) and not is_prime(mersenne(p)))
sage: next(counter_examples)
11
Exercises
建立列表 {{i^3 mid -10<i<10}} . 你能找到两个立方体吗 u 和 v 这样的话 u + v = 218 是吗?
sage: # edit here
迭代工具¶
它的名字表明 itertools
是一个模块,它定义了几个用于操作迭代器的便利工具:
sage: l = [3, 234, 12, 53, 23]
sage: [(i, l[i]) for i in range(len(l))]
[(0, 3), (1, 234), (2, 12), (3, 53), (4, 23)]
使用 enumerate()
::
sage: list(enumerate(l))
[(0, 3), (1, 234), (2, 12), (3, 53), (4, 23)]
下面是列表切片的模拟:
sage: list(Permutations(3))
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
sage: list(Permutations(3))[1:4]
[[1, 3, 2], [2, 1, 3], [2, 3, 1]]
sage: import itertools
sage: list(itertools.islice(Permutations(3), 1r, 4r))
[[1, 3, 2], [2, 1, 3], [2, 3, 1]]
请注意,所有调用 islice
必须具有类型为的参数 int
而不是Sage的整数。
函数的行为 map()
和 filter()
在Python2和Python3之间发生了变化。在python3中,它们返回一个迭代器。如果您想在python2中使用这种新行为,并保持代码与Python3兼容,那么可以使用兼容性库 six
如下:
sage: from six.moves import map
sage: list(map(lambda z: z.cycle_type(), Permutations(3)))
[[1, 1, 1], [2, 1], [2, 1], [3], [3], [2, 1]]
sage: from six.moves import filter
sage: list(filter(lambda z: z.has_pattern([1,2]), Permutations(3)))
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2]]
Exercises
为 i -th质数 5<i<10 ::
sage: # edit here
定义新迭代器¶
使用关键字可以很容易地编写新的迭代器 yield
. 下面的函数除了演示 yield
::
sage: def f(n):
....: for i in range(n):
....: yield i
sage: [ u for u in f(5) ]
[0, 1, 2, 3, 4]
迭代器可以是递归的:
sage: def words(alphabet,l):
....: if l == 0:
....: yield []
....: else:
....: for word in words(alphabet, l-1):
....: for a in alphabet:
....: yield word + [a]
sage: [ w for w in words(['a','b','c'], 3) ]
[['a', 'a', 'a'], ['a', 'a', 'b'], ['a', 'a', 'c'], ['a', 'b', 'a'], ['a', 'b', 'b'], ['a', 'b', 'c'], ['a', 'c', 'a'], ['a', 'c', 'b'], ['a', 'c', 'c'], ['b', 'a', 'a'], ['b', 'a', 'b'], ['b', 'a', 'c'], ['b', 'b', 'a'], ['b', 'b', 'b'], ['b', 'b', 'c'], ['b', 'c', 'a'], ['b', 'c', 'b'], ['b', 'c', 'c'], ['c', 'a', 'a'], ['c', 'a', 'b'], ['c', 'a', 'c'], ['c', 'b', 'a'], ['c', 'b', 'b'], ['c', 'b', 'c'], ['c', 'c', 'a'], ['c', 'c', 'b'], ['c', 'c', 'c']]
sage: sum(1 for w in words(['a','b','c'], 3))
27
这是另一个递归迭代器:
sage: def dyck_words(l):
....: if l==0:
....: yield ''
....: else:
....: for k in range(l):
....: for w1 in dyck_words(k):
....: for w2 in dyck_words(l-k-1):
....: yield '('+w1+')'+w2
sage: list(dyck_words(4))
['()()()()',
'()()(())',
'()(())()',
'()(()())',
'()((()))',
'(())()()',
'(())(())',
'(()())()',
'((()))()',
'(()()())',
'(()(()))',
'((())())',
'((()()))',
'(((())))']
sage: sum(1 for w in dyck_words(5))
42
Exercises
写一个有两个参数的迭代器 n , l 迭代一组小于 n 长度的 l ::
sage: # edit here
标准Iterables¶
最后,许多标准Python和Sage对象是 可迭代的 ;也就是说,可以迭代它们的元素:
sage: sum( x^len(s) for s in Subsets(8) )
x^8 + 8*x^7 + 28*x^6 + 56*x^5 + 70*x^4 + 56*x^3 + 28*x^2 + 8*x + 1
sage: sum( x^p.length() for p in Permutations(3) )
x^3 + 2*x^2 + 2*x + 1
sage: factor(sum( x^p.length() for p in Permutations(3) ))
(x^2 + x + 1)*(x + 1)
sage: P = Permutations(5)
sage: all( p in P for p in P )
True
sage: for p in GL(2, 2): print(p); print("")
[1 0]
[0 1]
<BLANKLINE>
[0 1]
[1 0]
<BLANKLINE>
[0 1]
[1 1]
<BLANKLINE>
[1 1]
[0 1]
<BLANKLINE>
[1 1]
[1 0]
<BLANKLINE>
[1 0]
[1 1]
<BLANKLINE>
sage: for p in Partitions(3): print(p)
[3]
[2, 1]
[1, 1, 1]
小心无限循环:
sage: for p in Partitions(): print(p) # not tested
sage: for p in Primes(): print(p) # not tested
无限循环仍然非常有用:
sage: exists( Primes(), lambda p: not is_prime(mersenne(p)) )
(True, 11)
sage: counter_examples = (p for p in Primes() if not is_prime(mersenne(p)))
sage: next(counter_examples)
11