Skip to content

Commit 79226b4

Browse files
authored
Merge pull request ictar#49 from ictar/pd_5
Pd 5
2 parents f9e2597 + d4d3820 commit 79226b4

6 files changed

+206
-1368
lines changed

Others/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,6 @@
118118

119119
- [Requests vs. urllib:它解决了什么问题?](./Requests vs. urllib:它解决了什么问题?.md)
120120

121-
- [更好的Python对象序列化方法](./更好的Python对象序列化方法.md)
121+
- [更好的Python对象序列化方法](./更好的Python对象序列化方法.md)
122+
123+
- [使用列表推导式实现zip](./使用列表推导式实现zip.md)
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
原文:[Implementing "zip" with list comprehensions](http://blog.lerner.co.il/implementing-zip-list-comprehensions/)
2+
3+
---
4+
5+
[![zipper](http://i1.wp.com/blog.lerner.co.il/wp-content/uploads/2016/08/zipper3.png?resize=150%2C300)](http://i1.wp.com/blog.lerner.co.il/wp-content/uploads/2016/08/zipper3.png)
6+
7+
我喜欢Python的"[zip](https://docs.python.org/3/library/functions.html#zip)"函数。我不大确定我喜欢zip什么,但是我常常发现它非常有用。在我描述"zip"做了什么之前,先让我告诉你一个例子:
8+
9+
```python
10+
>>> s = 'abc'
11+
>>> t = (10, 20, 30)
12+
13+
>>> zip(s,t)
14+
[('a', 10), ('b', 20), ('c', 30)]
15+
```
16+
17+
正如你所看到的,"zip"的结果是一个元组序列。(在Python 2中,你会得到一个列表。在Python 3中,你会得到一个"zip对象"。) 下标为0的元组包含s[0]和t[0]。下标为1的元组包含s[1]和t[1]。以此类推。你还可以对多于一个可迭代对象使用zip:
18+
19+
```python
20+
>>> s = 'abc'
21+
>>> t = (10, 20, 30)
22+
>>> u = (-5, -10, -15)
23+
24+
>>> list(zip(s,t,u))
25+
[('a', 10, -5), ('b', 20, -10), ('c', 30, -15)]
26+
```
27+
28+
(你还可以用一个可迭代对象来调用zip,从而获得一堆一元素元组,但这对我来说似乎有点奇怪。)
29+
30+
我常常使用"zip"来将并行序列转换成字典。例如:
31+
32+
```python
33+
>>> names = ['Tom', 'Dick', 'Harry']
34+
>>> ages = [50, 35, 60]
35+
36+
>>> dict(zip(names, ages))
37+
{'Harry': 60, 'Dick': 35, 'Tom': 50}
38+
```
39+
40+
通过这种方式,我们可以快速方便的从两个并行序列中生成一个字典。
41+
42+
每当我在我的编程班中提到"zip",难免有人会问,如果一个参数比另一个参数短,会发生什么事。简单地说,最短的那个获胜:
43+
44+
```python
45+
>>> s = 'abc'
46+
>>> t = (10, 20, 30, 40)
47+
>>> list(zip(s,t))
48+
[('a', 10), ('b', 20), ('c', 30)]
49+
```
50+
51+
(如果你想要zip为较长的可迭代对象中的每个元素返回一个元组,那么使用"[itertools](https://docs.python.org/3/library/itertools.html#module-itertools)"包中的"[izip_longest](https://docs.python.org/3/library/itertools.html#itertools.zip_longest)"。)
52+
53+
现在,如果还有什么比"zip"更让我喜欢的,那它就是列表推导式了。所以,上周,当我的一个学生问我,是否我们可以使用列表推导式来实现"zip"的时候,我无法抗拒。
54+
55+
所以,我们可以怎么做呢?
56+
57+
首先,让我们假设,从上面,我们有两个相同长度的序列,s(一个字符串)和t(一个元组)。我们想要获得一个包含三个元组的列表. 其中一个方法是:
58+
59+
```python
60+
[(s[i], t[i]) # produce a two-element tuple
61+
for i in range(len(s))] # from index 0 to len(s) - 1
62+
```
63+
64+
老实说,这工作良好!但我们还有可以改善它的一些方法。
65+
66+
首先,让我们基于推导式的"zip"选择性地处理不同大小的输入将是不错的。这意味着,不仅仅是运行range(len(s)),还运行range(len(x)),其中,x是较短的序列。我们可以通过内置函数"sorted"来做到这点,告诉它根据长度来对序列进行排序,从最短的到最长的。例如:
67+
68+
```python
69+
>>> s = 'abcd'
70+
>>> t = (10, 20, 30)
71+
72+
>>> sorted((s,t), key=len)
73+
[(10, 20, 30), 'abcd']
74+
```
75+
76+
在上面的代码中,我创建了一个新的元组:(s,t),然后将其作为第一个参数传递给"sorted"。给定这些输入,我们将从"sorted"获得一个列表。由于我们传递了内置的"len"函数给"key"参数,因此,如果s更短,那么"sorted"会返回[s,t],如果t更短,则返回[t,s]。这意味着,下标为0的元素保证不比其他任何序列长。(如果所有的序列都是相同的大小,那么,我们不在乎获得哪个。)
77+
78+
将这些一起放到我们的推导式中,获得:
79+
80+
```python
81+
>>> [(s[i], t[i])
82+
for i in range(len(sorted((s,t), key=len)[0]))]
83+
```
84+
85+
这对于一个单一的列表推导式有点复杂,因此,我将把第二行的一部分折断成一个函数,仅仅是为了把它弄得干净些:
86+
87+
```python
88+
>>> def shortest_sequence_range(*args):
89+
return range(len(sorted(args, key=len)[0]))
90+
91+
>>> [(s[i], t[i])
92+
for i in shortest_sequence_range(s,t) ]
93+
```
94+
95+
现在,我们的函数接收\*args,这意味着它可以接收任何数量的序列。序列们根据长度进行排序,然后传递第一个(最短的)序列给"len",该函数计算长度,然后返回运行"range"的结果。
96+
97+
因此,如果最短的序列是'abc',那么结果我们会返回range(3),它为我们提供索引0, 1, 和2 —— 满足我们所需。
98+
99+
现在,它离真正的"zip"还有点距离:正如我上面提到的,Python 2的"zip"函数返回一个列表,但是Python 3的"zip"返回一个可迭代对象。这意味着,即使返回的列表非常的长,我们也不会因为一次性将其全部返回而占用大量的内存。我们可以用推导式来做到这点吗?
100+
101+
是哒,但如果我们使用列表推导式是做不到的,它总是返回一个列表。相反,如果我们使用一个生成器表达式,那么我们将会活动一个迭代器,而不是整个列表。幸运的是,创建这样一个生成器表达式只是将我们的列表推导式的[ ]替换成生成器表达式的( )这么简单而已:
102+
103+
```python
104+
>>> def shortest_sequence_range(*args):
105+
return range(len(sorted(args, key=len)[0]))
106+
107+
>>> g = ((s[i], t[i])
108+
for i in shortest_sequence_range(s,t) )
109+
110+
>>> for item in g:
111+
print(item)
112+
('a', 10)
113+
('b', 20)
114+
('c', 30)
115+
```
116+
117+
现在你明白了!欢迎对这些想法做进一步改善 —— 但作为同时喜欢"zip"和推导式的人,将这两个概念联系在一起是很有趣的。

Python Common/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,8 @@
5454

5555
- [Lists和Tuples大对决](./Lists和Tuples大对决.md)
5656

57-
常见的Python初学者问题:列表和元组之间有何区别?答案是,有两个不同的差异,以及两者之复杂的相互作用。这就是技术差异和文化差异。
57+
常见的Python初学者问题:列表和元组之间有何区别?答案是,有两个不同的差异,以及两者之复杂的相互作用。这就是技术差异和文化差异。
58+
59+
- [解释python中的*args和**kwargs](./解释python中的*args和**kwargs.md)
60+
61+
我发现,大多数的Python新手程序员很难搞清楚\*args和\*\*kwargs魔术变量。所以,它们是什么呢?
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
原文:[\*args and **kwargs in python explained](https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/)
2+
3+
---
4+
5+
嘿,大家好呀。我发现,大多数的Python新手程序员很难搞清楚\*args和\*\*kwargs魔术变量。所以,它们是什么呢?首先,让我告诉你,写\*args或者\*\*kwargs并不是必须的。只有\*(星号)是必须的。你也可以写成\*var和\*\*vars。写成\*args和\*\*kwargs仅仅是一个惯例。所以,让我们先来看看*args。
6+
7+
** *args的使用 **
8+
\*args和\*\*kwargs最常用于函数定义。\*args和\*\*kwargs允许你传递数量不定的参数给一个函数。这里的变量的意思是,你事先不知道用户会传递多少个变量给你的函数,因此,在这种情况下,你使用这两个关键字。\*args是用来发送一个**非关键字**可变长度的变量列表给函数。这里是一个例子,以助你弄明白:
9+
10+
```python
11+
def test_var_args(f_arg, *argv):
12+
print "first normal arg:", f_arg
13+
for arg in argv:
14+
print "another arg through *argv :", arg
15+
16+
test_var_args('yasoob','python','eggs','test')
17+
```
18+
19+
这生成以下结果:
20+
21+
```
22+
first normal arg: yasoob
23+
another arg through *argv : python
24+
another arg through *argv : eggs
25+
another arg through *argv : test
26+
```
27+
28+
我希望这解开了你的困惑。现在,让我们谈谈\*\*kwargs
29+
30+
**\*\*kwargs的使用**
31+
\*\*kwargs运行你传递**关键字**可变长度参数给函数。如果你想要处理函数中的**命名参数**,那么你应该使用\*\*kwargs。下面是一个例子,以帮助理解它:
32+
33+
```python
34+
def greet_me(**kwargs):
35+
if kwargs is not None:
36+
for key, value in kwargs.iteritems():
37+
print "%s == %s" %(key,value)
38+
39+
>>> greet_me(name="yasoob")
40+
name == yasoob
41+
```
42+
43+
所以,你可以看到我们是如何在函数中处理一个关键字参数列表的。这仅仅是\*\*kwargs的基础知识,而你可以看到它多有用。现在,让我们聊聊你可以如何使用\*args和\*\*kwargs,利用一个参数列表或者参数字典来调用一个函数。
44+
45+
**使用*args和\*\*kwargs来调用一个函数**
46+
所以在这里,我们会看到如何使用\*args和\*\*kwargs来调用一个函数。试想,你有这么一个小函数:
47+
48+
```python
49+
def test_args_kwargs(arg1, arg2, arg3):
50+
print "arg1:", arg1
51+
print "arg2:", arg2
52+
print "arg3:", arg3
53+
```
54+
55+
现在,你可以使用\*args或者\*\*kwargs来传递参数给这个小函数。以下是如何做到这点:
56+
57+
```python
58+
# first with *args
59+
>>> args = ("two", 3,5)
60+
>>> test_args_kwargs(*args)
61+
arg1: two
62+
arg2: 3
63+
arg3: 5
64+
65+
# now with **kwargs:
66+
>>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
67+
>>> test_args_kwargs(**kwargs)
68+
arg1: 5
69+
arg2: two
70+
arg3: 3
71+
```
72+
73+
**使用*args、\*\*kwargs以及普通参数的顺序**
74+
所以,如果你想要在函数中同时使用这三个,那么顺序是
75+
76+
```python
77+
some_func(fargs,*args,**kwargs)
78+
```
79+
80+
我希望你明白了\*args和\*\*kwargs的使用。如果你对其有任何疑问或困惑,那么请随意在下面留言。要进一步研究,我推荐官方的[关于定义函数的python文档](http://docs.python.org/tutorial/controlflow.html#more-on-defining-functions),以及[stackoverflow上的\*args和**kwargs](http://stackoverflow.com/questions/3394835/args-and-kwargs)
81+

0 commit comments

Comments
 (0)