Skip to content

Commit 26dbbf9

Browse files
committed
2.14小节完成
1 parent 1badd6a commit 26dbbf9

3 files changed

Lines changed: 207 additions & 3 deletions

File tree

cookbook/c02/p14_join_str.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
"""
4+
Topic: 字符串合并
5+
Desc :
6+
"""
7+
8+
9+
def combine(source, maxsize):
10+
parts = []
11+
size = 0
12+
for part in source:
13+
parts.append(part)
14+
size += len(part)
15+
if size > maxsize:
16+
yield ''.join(parts)
17+
parts = []
18+
size = 0
19+
yield ' '.join(parts)
20+
21+
22+
def sample():
23+
yield 'Is'
24+
yield 'Chicago'
25+
yield 'Not'
26+
yield 'Chicago?'
27+
28+
29+
def join_str():
30+
parts = ['Is', 'Chicago', 'Not', 'Chicago?']
31+
print(' '.join(parts))
32+
print(','.join(parts))
33+
print(''.join(parts))
34+
35+
# 使用+
36+
a = 'Is Chicago'
37+
b = 'Not Chicago?'
38+
c = 'ccc'
39+
print(a + ' ' + b)
40+
41+
data = ['ACME', 50, 91.1]
42+
print(','.join(str(d) for d in data))
43+
44+
45+
print(a + ':' + b + ':' + c) # Ugly
46+
print(':'.join([a, b, c])) # Still ugly
47+
print(a, b, c, sep=':') # Better
48+
49+
# 混合方案
50+
# with open('filename', 'w') as f:
51+
# for part in combine(sample(), 32768):
52+
# f.write(part)
53+
for part in combine(sample(), 32768):
54+
print(part)
55+
56+
if __name__ == '__main__':
57+
join_str()
58+

source/c02/p13_aligning_text_strings.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
----------
88
你想通过某种对齐方式来格式化字符串
99

10+
|
11+
1012
----------
1113
解决方案
1214
----------

source/c02/p14_combine_and_concatenate_strings.rst

Lines changed: 147 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,158 @@
55
----------
66
问题
77
----------
8-
todo...
8+
你想将几个小的字符串合并为一个大的字符串
9+
10+
|
911
1012
----------
1113
解决方案
1214
----------
13-
todo...
15+
如果你想要合并的字符串是在一个序列或者iterable中,那么最快的方式就是使用join()方法。比如:
16+
17+
.. code-block:: python
18+
19+
>>> parts = ['Is', 'Chicago', 'Not', 'Chicago?']
20+
>>> ' '.join(parts)
21+
'Is Chicago Not Chicago?'
22+
>>> ','.join(parts)
23+
'Is,Chicago,Not,Chicago?'
24+
>>> ''.join(parts)
25+
'IsChicagoNotChicago?'
26+
>>>
27+
28+
初看起来,这种语法看上去会比较怪,但是join()被指定为字符串的一个方法。
29+
这样做的部分原因是你想去连接的对象可能来自各种不同的数据序列(比如列表,元组,字典,文件,集合或生成器等),
30+
如果在所有这些对象上都定义一个join()方法明显是冗余的。
31+
因此你只需要指定你想要的分割字符串并调用他的join()方法去将文本片段组合起来。
32+
33+
如果你仅仅只是合并少数几个字符串,使用加号(+)通常已经足够了:
34+
35+
.. code-block:: python
36+
37+
>>> a = 'Is Chicago'
38+
>>> b = 'Not Chicago?'
39+
>>> a + ' ' + b
40+
'Is Chicago Not Chicago?'
41+
>>>
42+
43+
加号(+)操作符在作为一些复杂字符串格式化的替代方案的时候通常也工作的很好,比如:
44+
45+
.. code-block:: python
46+
47+
>>> print('{} {}'.format(a,b))
48+
Is Chicago Not Chicago?
49+
>>> print(a + ' ' + b)
50+
Is Chicago Not Chicago?
51+
>>>
52+
53+
如果你想在源码中将两个字面字符串合并起来,你只需要简单的将它们放到一起,不需要用加号(+)。比如:
54+
55+
.. code-block:: python
56+
57+
>>> a = 'Hello' 'World'
58+
>>> a
59+
'HelloWorld'
60+
>>>
61+
62+
|
1463
1564
----------
1665
讨论
1766
----------
18-
todo...
67+
字符串合并可能看上去并不需要用一整节来讨论。
68+
但是不应该小看这个问题,程序员通常在字符串格式化的时候因为选择不当而给应用程序带来严重性能损失。
69+
70+
最重要的需要引起注意的是,当我们使用加号(+)操作符去连接大量的字符串的时候是非常低效率的,
71+
因为加号连接会引起内存复制以及垃圾回收操作。
72+
特别的,你永远都不应像下面这样写字符串连接代码:
73+
74+
.. code-block:: python
75+
76+
s = ''
77+
for p in parts:
78+
s += p
79+
80+
这种写法会比使用join()方法运行的要慢一些,因为每一次执行+=操作的时候会创建一个新的字符串对象。
81+
你最好是先收集所有的字符串片段然后再将它们连接起来。
82+
83+
一个相对比较聪明的技巧是利用生成器表达式(参考1.19小节)转换数据为字符串的同时合并字符串,比如:
84+
85+
.. code-block:: python
86+
87+
>>> data = ['ACME', 50, 91.1]
88+
>>> ','.join(str(d) for d in data)
89+
'ACME,50,91.1'
90+
>>>
91+
92+
同样还得注意不必要的字符串连接操作。有时候程序员在没有必要做连接操作的时候仍然多此一举。比如在打印的时候:
93+
94+
.. code-block:: python
95+
96+
print(a + ':' + b + ':' + c) # Ugly
97+
print(':'.join([a, b, c])) # Still ugly
98+
print(a, b, c, sep=':') # Better
99+
100+
当混合使用I/O操作和字符串连接操作的时候,有时候需要仔细研究你的程序。
101+
比如,考虑下面的两端代码片段:
102+
103+
.. code-block:: python
104+
105+
# Version 1 (string concatenation)
106+
f.write(chunk1 + chunk2)
107+
108+
# Version 2 (separate I/O operations)
109+
f.write(chunk1)
110+
f.write(chunk2)
111+
112+
如果两个字符串很小,那么第一个版本性能会更好些,因为I/O系统调用天生就慢。
113+
另外一方面,如果两个字符串很大,那么第二个版本可能会更加高效,
114+
因为它避免了创建一个很大的临时结果并且要复制大量的内存块数据。
115+
还是那句话,有时候是需要根据你的应用程序特点来决定应该使用哪种方案。
116+
117+
最后谈一下,如果你准备编写构建大量小字符串的输出代码,你最好考虑下使用生成器函数,利用yield语句产生输出片段。比如:
118+
119+
.. code-block:: python
120+
121+
def sample():
122+
yield 'Is'
123+
yield 'Chicago'
124+
yield 'Not'
125+
yield 'Chicago?'
126+
127+
这种方法一个有趣的方面是它并没有对输出片段到底要怎样组织做出假设。
128+
例如,你可以简单的使用join()方法将这些片段合并起来:
129+
130+
.. code-block:: python
131+
132+
text = ''.join(sample())
133+
134+
或者你也可以将字符串片段重定向到I/O:
135+
136+
.. code-block:: python
137+
138+
for part in sample():
139+
f.write(part)
140+
141+
再或者你还可以写出一些结合I/O操作的混合方案:
142+
143+
.. code-block:: python
144+
145+
def combine(source, maxsize):
146+
parts = []
147+
size = 0
148+
for part in source:
149+
parts.append(part)
150+
size += len(part)
151+
if size > maxsize:
152+
yield ''.join(parts)
153+
parts = []
154+
size = 0
155+
yield ''.join(parts)
156+
157+
# 结合文件操作
158+
with open('filename', 'w') as f:
159+
for part in combine(sample(), 32768):
160+
f.write(part)
161+
162+
这里的关键点在于原始的生成器函数并不需要知道使用细节,它只负责生成字符串片段就行了。

0 commit comments

Comments
 (0)