鱼C论坛

 找回密码
 立即注册
楼主: lightninng

[技术交流] [记录贴]每天的问题和解决方法_正确学习方法

[复制链接]
发表于 2015-4-30 14:57:00 | 显示全部楼层
lightninng 发表于 2015-4-30 12:46
三天没来了,今天看到了甲鱼之前转的一篇帖子,说到了代码整洁之道,看到了变量命名的问题,Python这门语言 ...

之前也纠结过这个问题, 后来决定一律用小峰驼法。:)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-30 15:53:32 | 显示全部楼层

每节的红字都是问题,以及解决我解决这个问题的方法,有兴趣可以想想,然后发贴交流,相互学习嘛
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-30 15:57:10 | 显示全部楼层
~风介~ 发表于 2015-4-30 14:57
之前也纠结过这个问题, 后来决定一律用小峰驼法。:)

恩,主要是积重难返,之前做那个的时候都是简单的小模块程序,我就全改成PEP 8的写法,这次最后一章是一个完整小游戏,作者的程序中全部用的都是小驼峰,让我有些犹豫~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-4-30 17:15:13 | 显示全部楼层
lightninng 发表于 2015-4-30 15:57
恩,主要是积重难返,之前做那个的时候都是简单的小模块程序,我就全改成PEP 8的写法,这次最后一章是一 ...

这种需要慢慢来——就像忘记一个人...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-6 00:17:43 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-6 00:19 编辑

上一次更这个贴子已经是6天前了,最近pyqt那个贴遇到瓶颈,自己又在改论文不想去弄它(说明变懒了),五一本来想把论文写好,因为各种各样的原因反而玩了4天,今天写了一天论文,到晚上莫名其妙的电脑开始频繁死机,最后一次死机直接打不开了,吓的我一身冷汗(10号之前要把论文交上去),最后想到手机还插在上面,果然拔掉手机电脑又打开了,我在想老天是不是惩罚我这几天不干活啊,pyqt那个暂时不更,但是每天还是要学点东西,正好之前找到了python cook book第三版的英文版,以及一位大神正在施工中的中文版,准备每天看一些,有兴趣的朋友网址如下:http://python3-cookbook.readthedocs.org/zh_CN/latest/
1、任何的序列(或者是可迭代对象)可以通过一个简单的赋值语句解压并赋值给多个变量
直接引用原文的例子
  1. >>> p = (4, 5)
  2. >>> x, y = p
  3. >>> x
  4. 4
  5. >>> y
  6. 5
  7. >>>
  8. >>> data = [ 'ACME', 50, 91.1, (2012, 12, 21) ]
  9. >>> name, shares, price, date = data
  10. >>> name
  11. 'ACME'
  12. >>> date
  13. (2012, 12, 21)
  14. >>> name, shares, price, (year, mon, day) = data
  15. >>> name
  16. 'ACME'
  17. >>> year
  18. 2012
  19. >>> mon
  20. 12
  21. >>> day
  22. 21
  23. >>>
复制代码
PS:这个方法在python中极为常用,如你想将两个变量(假如这两个变量是x,y)的赋值进行交换时,python中可以这样写x, y = y, x;同理 这个方法可以拓展到任意个变量作任意方式的交换
有时候,你可能只想解压一部分,丢弃其他的值。对于这种情况Python并没有提供特殊的语法。 但是你可以使用任意变量名去占位,到时候丢掉这些变量就行了。
  1. >>> data = [ 'ACME', 50, 91.1, (2012, 12, 21) ]
  2. >>> _, shares, price, _ = data
  3. >>> shares
  4. 50
  5. >>> price
  6. 91.1
  7. >>>
复制代码
PS:说到占位符,最先想到的是C语言中字符串格式化的占位符(当然python中也有),这里的占位符其实是一个变量,python中允许使用_开头的变量,这个例子中的_其实是一个变量名,当然你可以用任何一个你不会使用的变量名作为占位符,但是_是一个比较好的选择,另外书中提到的另外一个不错的选择是 ign,我觉得这没有为什么,可能只是一种约定俗成


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-5-6 12:11:48 | 显示全部楼层
有部分还看不懂,全学会再回来看看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-5-6 16:22:29 | 显示全部楼层
楼主棒棒哒,我是来赚取鱼币的:lol:
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-6 22:58:17 | 显示全部楼层
shenxiang839 发表于 2015-5-6 12:11
有部分还看不懂,全学会再回来看看

最近应该持续会更Python cook book当中的内容,不算难,而且体现python这门语言的特点,欢迎来交流~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-6 23:13:25 | 显示全部楼层
问题:如果一个可迭代对象的元素个数超过变量个数时,会出现”太多解压值”的异常。 那么怎样才能从这个可迭代对象中解压出N个元素出来?
解决:Python的星号表达式可以用来解决这个问题
比如,你在学习一门课程,在学期末的时候, 你想统计下家庭作业的平均成绩,但是排除掉第一个和最后一个分数。如果只有四个分数,你可能就直接去简单的手动赋值, 但如果有24个呢?这时候星号表达式就派上用场了:
  1. def drop_first_last(grades):
  2.     first, *middle, last = grades
  3.     return avg(middle)
复制代码
另外一种情况,假设你现在有一些用户的记录列表,每条记录包含一个名字、邮件,接着就是不确定数量的电话号码。 你可以像下面这样分解这些记录:
  1. >>> record = ('Dave', 'dave@example.com', '773-555-1212', '847-555-1212')
  2. >>> name, email, *phone_numbers = user_record
  3. >>> name
  4. 'Dave'
  5. >>> email
  6. 'dave@example.com'
  7. >>> phone_numbers
  8. ['773-555-1212', '847-555-1212']
  9. >>>
复制代码
PS:这个方法也相当的常用,不过看到这个我想起的是甲鱼小哥的视频,我想看过甲鱼小哥视频中函数那几集的鱼油,应该都记得函数的参数中有一种叫作收集参数(我忘了甲鱼小哥把它叫什么了),这种参数在函数定义时用的正是*args这种写法,传入的参数正是一个列表,这里用*表达式解压得到的也是一个列表(哪怕它只有一个元素)

原文中给出的另外两个例子如下(我就全贴了,因为我觉得例子比描述更有说服力):
  1. """带有标签的元组序列"""
  2. records = [
  3.     ('foo', 1, 2),
  4.     ('bar', 'hello'),
  5.     ('foo', 3, 4),
  6. ]

  7. def do_foo(x, y):
  8.     print('foo', x, y)

  9. def do_bar(s):
  10.     print('bar', s)

  11. for tag, *args in records:
  12.     if tag == 'foo':
  13.         do_foo(*args)
  14.     elif tag == 'bar':
  15.         do_bar(*args)
复制代码
  1. """字符串分割"""
  2. >>> line = 'nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false'
  3. >>> uname, *fields, homedir, sh = line.split(':')
  4. >>> uname
  5. 'nobody'
  6. >>> homedir
  7. '/var/empty'
  8. >>> sh
  9. '/usr/bin/false'
  10. >>>
复制代码
  1. """和昨天一样的占位符,_取到的内容是自己不需要的"""
  2. >>> record = ('ACME', 50, 123.45, (12, 18, 2012))
  3. >>> name, *_, (*_, year) = record
  4. >>> name
  5. 'ACME'
  6. >>> year
  7. 2012
  8. >>>
复制代码

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-5-7 10:31:23 | 显示全部楼层
还没入门,看你的帖子还看不懂,但是你的学习方法给了我很好的榜样,希望以后能多多交流学习:loveliness:
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-7 12:24:24 | 显示全部楼层
小小云儿 发表于 2015-5-7 10:31
还没入门,看你的帖子还看不懂,但是你的学习方法给了我很好的榜样,希望以后能多多交流学习

欢迎交流~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-7 23:17:02 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-7 23:25 编辑

在迭代操作或者其他操作的时候,怎样只保留最后有限几个元素的历史记录?
保留有限历史记录正是 collections.deque 大显身手的时候。比如,下面的代码在多行上面做简单的文本匹配, 并只返回在前N行中匹配成功的行:
  1. from collections import deque


  2. def search(lines, pattern, history=5):
  3.     previous_lines = deque(maxlen=history)
  4.     for li in lines:
  5.         if pattern in li:
  6.             yield li, previous_lines
  7.         previous_lines.append(li)

  8. # Example use on a file
  9. if __name__ == '__main__':
  10.     with open(r'../../cookbook/somefile.txt') as f:
  11.         for line, prevlines in search(f, 'python', 5):
  12.             for pline in prevlines:
  13.                 print(pline, end='')
  14.             print(line, end='')
  15.             print('-' * 20)
复制代码
PS:上面的例子,中我自己学习到的地方:

1、通过yield语句返回的函数,生成的函数叫作生成器函数,它返回的是一个可迭代对象(最典型的例子就是我们经常会用到的range()),不懂yield语句的朋友请移步http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00138681965108490cb4c13182e472f8d87830f13be6e88000

2、函数可以传入一个可迭代对象或者生成器(其实这个早已经知道了,之前学到的itertools.product()),在这个例子中传入search()函数的第一个参数是一个文件对象,它通过迭代不停的寻找匹配项加入previous_lines中
3、collections模块的deque(即双端队列)在戴宇轩小哥的http://bbs.fishc.com/forum.php?mod=viewthread&tid=59409&ctid=157这个贴子中已经介绍过,当时没有太多的想法,看到这个例子想起了一些东西:
(1)deque这种数据对象在队列头部插入时时间复杂度都为O(1),和list对象的O(n)相比效率提高太多,
(2)这个例子中给我们演示了deque的参数maxlen
(3)deque这个数据结构可以方便的使用appendleft和append方法在两端插入元素,当元素总数超过maxlen时,会从另一端删除元素,正是这个特性使我们可以保留最近n个数据
还是原书关于deque的例子,我把它稍作修改,使得最后一次插入元素从左侧插入,因为元素总数超过3,所以会从右侧删除一个元素
  1. >>> q = deque(maxlen=3)
  2. >>> q.append(1)
  3. >>> q.append(2)
  4. >>> q.append(3)
  5. >>> q
  6. deque([1, 2, 3], maxlen=3)
  7. >>> q.append(4)
  8. >>> q
  9. deque([2, 3, 4], maxlen=3)
  10. >>> q.appendleft(5)
  11. >>> q
  12. deque([5, 2, 3], maxlen=3)
复制代码






想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-9 00:57:25 | 显示全部楼层
问题:怎样从一个集合中获得最大或者最小的N个元素列表?
解决:heapq模块有两个函数:nlargest()nsmallest() 可以完美解决这个问题。
  1. import heapq
  2. nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
  3. print(heapq.nlargest(3, nums)) # Prints [42, 37, 23]
  4. print(heapq.nsmallest(3, nums)) # Prints [-4, 1, 2]
复制代码
两个函数都能接受一个关键字参数,用于更复杂的数据结构中:
  1. portfolio = [
  2.     {'name': 'IBM', 'shares': 100, 'price': 91.1},
  3.     {'name': 'AAPL', 'shares': 50, 'price': 543.22},
  4.     {'name': 'FB', 'shares': 200, 'price': 21.09},
  5.     {'name': 'HPQ', 'shares': 35, 'price': 31.75},
  6.     {'name': 'YHOO', 'shares': 45, 'price': 16.35},
  7.     {'name': 'ACME', 'shares': 75, 'price': 115.65}
  8. ]
  9. cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
  10. expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
复制代码
PS:这个参数key,用max和min两个函数用的多的同学相信比较熟悉了,不懂的,先去看看max和min两个函数的key参数,举一反三,这里的key参数是同样 的用法
根据原书中的说法,这两个函数实际上是对列表中的元素进行了堆排序,堆是一种数据结构, 基本上只要是数据结构和算法书籍里面都会有提及到,不知道甲鱼小哥的数据结构视频中有否提到,但它确实一种很有用的数据结构,由其是这个问题中所遇到的情况。
另外,你可以用heapq.heapify()函数将一个列表转化为堆,转化为堆后,列表的第一个元素是最小的元素
  1. >>> nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
  2. >>> import heapq
  3. >>> heapq.heapify(nums)
  4. >>> nums
  5. [-4, 2, 1, 23, 7, 2, 18, 23, 42, 37, 8]
  6. >>>
复制代码
另外 ,你可以用
heapq.heappop()函数弹出最小的元素,并将剩下的元素依然保持为堆结构,换句话说,该函数会先将第一个元素弹出来,然后用下一个最小的元素来取代被弹出元素(这种操作时间复杂度仅仅是O(N),N是堆大小,这里的时间复杂度指的是最坏情况下的时间复杂度)。这样我们想找最小的三个元素只需要调用三次heapq.heappop()函数即可
最后,书的作者提醒我们nlargest() 和 nsmallest()这两个函数在你需要找的元素远小于总元素个数时,效率不错,但当你要找的元素个数接近总元素个数时,用这两个函数不如你直接排序加列表切片来的实在,正如作者所说在正确的场合使用正确的工具才能让你的工作进行的更有效率。





想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-5-9 09:11:29 | 显示全部楼层
lightninng 发表于 2015-4-3 10:30
谢谢,学习中,多交流感觉学的更快~~
欢迎吐槽~~

{:1_1:}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-10 00:55:43 | 显示全部楼层
问题:怎样实现一个按优先级排序的队列? 并且在这个队列上面每次pop操作总是返回优先级最高的那个元素
解决:下面的类利用heapq模块实现了一个简单的优先级队列,该队列调用pop()方法可弹出优先级最高的元素,如果优先级最高的元素有多个,则按插入顺序返回最先插入的元素
  1. import heapq

  2. class PriorityQueue:
  3.     def __init__(self):
  4.         self._queue = []
  5.         self._index = 0

  6.     def push(self, item, priority):
  7.         heapq.heappush(self._queue, (-priority, self._index, item))
  8.         self._index += 1

  9.     def pop(self):
  10.         return heapq.heappop(self._queue)[-1]
复制代码
在上面代码中,队列包含了一个 (-priority, index, item) 的元组。 优先级为负数的目的是使得元素按照优先级从高到低排序。 这个跟普通的按优先级从低到高排序的堆排序恰巧相反。
index变量的作用是保证同等优先级元素的正确排序,也就是说index表明这个元素是第几个插入的元素。 通过保存一个不断增加的index下标变量,可以确保元素安装它们插入的顺序排序。 而且,index变量也在相同优先级元素比较的时候起到重要作用。
PS:昨天的那个小节,我们已经接触到了heapq这个模块,知道它相关的函数其实是把列表按堆的方式排序,这里的heappop()函数昨天已经介绍过,heappush与其相反, 是给列表插入一个元素,然后再重新把插入后的列表建成堆,看到这里我有点不能理解,因为这里列表的元素是元组,怎么排序呢?看了看说明,感觉可能是按每个元组的第一个元素排序,如果两个元组第一个元素相同 ,则按第二个元素确定它们的次序,以此类推下去,用max函数验证如下:
  1. >>> max_test = list(zip(range(10), range(-10,1)))
  2. >>> max_test
  3. [(0, -10), (1, -9), (2, -8), (3, -7), (4, -6), (5, -5), (6, -4), (7, -3), (8, -2), (9, -1)]
  4. >>> max(max_test)
  5. (9, -1)
  6. >>> max_test.append((9, 1))
  7. >>> max_test.append((9, -2))
  8. >>> max_test
  9. [(0, -10), (1, -9), (2, -8), (3, -7), (4, -6), (5, -5), (6, -4), (7, -3), (8, -2), (9, -1), (9, 1), (9, -2)]
  10. >>> max(max_test)
  11. (9, 1)
  12. >>>
复制代码




想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-11 01:02:26 | 显示全部楼层
问题:怎样实现一个键对应多个值的字典(也叫 multidict )?
解决:使用collections模块中的defaultdict来构造值(value)为列表、集合或字典的字典
  1. from collections import defaultdict

  2. d = defaultdict(list)
  3. d['a'].append(1)
  4. d['a'].append(2)
  5. d['b'].append(4)
  6. print(d)
  7. d = defaultdict(set)
  8. d['a'].add(1)
  9. d['a'].add(2)
  10. d['b'].add(4)
  11. print(d)
  12. d['a'].update({1:"a"})
  13. d['a'].update({2:"b"})
  14. d['a'].update({3:"c"})
  15. print(d)
复制代码
这段代码的输出如下

  1. >>> ================================ RESTART ================================
  2. >>>
  3. defaultdict(<class 'list'>, {'a': [1, 2], 'b': [4]})
  4. defaultdict(<class 'set'>, {'a': {1, 2}, 'b': {4}})
  5. defaultdict(<class 'dict'>, {'a': {1: 'a', 2: 'b', 3: 'c'}})
  6. >>>
复制代码
PS:相信看到戴小哥的这个贴子的鱼友http://bbs.fishc.com/forum.php?mod=viewthread&tid=59396&ctid=157,会想起字典的这个方法setdefault(k[, d]),我自己在做论文时遇到这个问题正是用的它比如这样
  1. d = {} # A regular dictionary
  2. d.setdefault('a', []).append(1)
  3. d.setdefault('a', []).append(2)
  4. d.setdefault('b', []).append(4)
  5. print(d)
复制代码
这段代码的输出是这样的
  1. >>> ================================ RESTART ================================
  2. >>>
  3. {'b': [4], 'a': [1, 2]}
  4. >>>
复制代码
setdefault()用起来有点别扭。因为每次调用都得创建一个新的初始值的实例(例子程序中的空列表[])。
  1. d = {}
  2. for key, value in pairs:
  3.     if key not in d:
  4.         d[key] = []
  5.     d[key].append(value)
复制代码
先检查键是否在字典中,如果不存在则先添加键值如果使用defaultdict的话就简单多了
  1. d = defaultdict(list)
  2. for key, value in pairs:
  3.     d[key].append(value)
复制代码
相信只要作数据处理,都会遇到这个问题,这个技巧可以说是相当 的实用



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-11 23:36:12 | 显示全部楼层
我们都知道字典中键值排列的顺序是和插入顺序无关的,也就是说在根据键值顺序进行迭代时,迭代的顺序和插入顺序可能会不同(这个可能性相当的大),那么问题来了
问题:想创建一个字典,并且在迭代或序列化这个字典的时候能够控制元素的顺序。
解决:使用collections模块中的OrderedDict类。
  1. from collections import OrderedDict

  2. d = OrderedDict()
  3. d['foo'] = 1
  4. d['bar'] = 2
  5. d['spam'] = 3
  6. d['grok'] = 4
  7. for key in d:
  8.     print(key, d[key])
复制代码
这个例子的输出如下

  1. >>> ================================ RESTART ================================
  2. >>>
  3. foo 1
  4. bar 2
  5. spam 3
  6. grok 4
  7. >>>
复制代码
另外,如果你想精确控制以JSON编码后字段的顺序,你可以先使用OrderedDict来构建这样的数据d,然后用下面的方法:
  1. >>> import json
  2. >>> json.dumps(d)
  3. '{"foo": 1, "bar": 2, "spam": 3, "grok": 4}'
  4. >>>
复制代码
PS:以上是用法,作者还提醒我们,orderdict类是用一个链表结构来维护键的插入顺序的,所以字典的大小将是普通字典的两倍,所以当你创建一个很大的字典的时候,需要考虑一下内存占用的问题,这是一个相当实际的问题,我用普通的字典处理一个有1w个键值的字典,字典的值均为长度为10的列表,我的8G内存就已经快抗不住了~~


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-13 01:16:50 | 显示全部楼层
今天的问题也是一个实际的问题
问题:怎样在数据字典中执行一些计算操作(比如求最小值、最大值、排序等等)?
解决:使用zip()函数先将键和值反转过来,具体见下面的例子

  1. prices = {
  2.     'ACME': 45.23,
  3.     'AAPL': 612.78,
  4.     'IBM': 205.55,
  5.     'HPQ': 37.20,
  6.     'FB': 10.75
  7. }
  8. min_price = min(zip(prices.values(), prices.keys()))
  9. print(min_price)
  10. max_price = max(zip(prices.values(), prices.keys()))
  11. print(max_price)
复制代码
这段代码的输出为

  1. >>> ================================ RESTART ================================
  2. >>>
  3. (10.75, 'FB')
  4. (612.78, 'AAPL')
  5. >>>
复制代码
可以看到,这里作的是对键值的排序操作,返回值是(值,键)的元组,有些同学可能会想到运用min或者max的key参数达到同样的效果,比如下面这样

  1. >>> min(prices, key=lambda k: prices[k])
  2. 'FB'
  3. >>> max(prices, key=lambda k: prices[k])
  4. 'AAPL'
复制代码
得到了值为最大和最小的键,但是如果你想获得最大值和最小值,还得再做一次字典的取值操作

可以看到,两者的效率应该是差不多的,但是通过元组的方法在使用的时候更加的灵活,这里又用到了之前提到的元组的比较,即以元组的第一个元素的大小关系为两个元素的大小关系,当第一个元素相同时,才会用到第二个元素,以此类推广,所以当两个键的值都最为最大(或最小)时 ,会返回键值更大(或小)的那一对(值,键)元组
另外 ,肯定有鱼油发现了当你对字典进行求最大(或最小)值时,实际是求键的最大(或最小)值,同样你直接对字典进行迭代时,实际是对键进行迭代即下面两组语句效果是相同的:
  1. for each in prices:
  2.     print(each)
  3. #--------------------------------------------------
  4. for each in prices.keys():
  5.     print(each)
复制代码
最后需要注意的一个问题是:
执行这些计算的时候,需要注意的是zip()函数创建的是一个只能访问一次的迭代器。来看一个例子:
  1. prices_and_names = zip(prices.values(), prices.keys())
  2. print(min(prices_and_names)) # OK
  3. print(max(prices_and_names)) # ValueError: max() arg is an empty sequence
复制代码
它的结果为:

  1. >>> ================================ RESTART ================================
  2. >>>
  3. (10.75, 'FB')
  4. Traceback (most recent call last):
  5.   File "C:\Users\Administrator\Desktop\11.py", line 10, in <module>
  6.     print(max(prices_and_names)) # ValueError: max() arg is an empty sequence
  7. ValueError: max() arg is an empty sequence
  8. >>>
复制代码
当然迭代器的每一项是在迭代过程中生成的,所以并不占用内存,所以一次或者两次都无所谓,但是如果多次使用最大或者最小值,或者你想得到第三大,或者第四大的值对应的(值,键)对时,最好还是专门创建一个列表来存放它们,比如这样:

  1. prices_sorted = sorted(zip(prices.values(), prices.keys()))
复制代码
PS:要说的话,这个问题遇到的还真的还是满多的,楼主悔恨中,当初要是看了这本书再写论文要省好多事的~~







想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-15 00:49:33 | 显示全部楼层
问题:怎样在两个字典中寻寻找相同点(比如相同的键、相同的值等等)?
解决:用集合操作
  1. a = {
  2.     'x' : 1,
  3.     'y' : 2,
  4.     'z' : 3
  5. }

  6. b = {
  7.     'w' : 10,
  8.     'x' : 11,
  9.     'y' : 2
  10. }
复制代码

对于上面两个字典,我们怎么求得它们相同的键(或者键值对)不同的键呢?
  1. >>> a.keys() & b.keys()
  2. {'x', 'y'}
  3. >>> a.items() & b.items()
  4. {('y', 2)}
  5. >>> a.keys() - b.keys()
  6. {'z'}
复制代码

PS:以及相信大家在平时的编程过程中用到最多的容器是list和dict两种了吧,对于集合set有些同学可能比较陌生,不过甲鱼小哥的视频中是有讲过的,集合有几个特点:
1、集合中元素不可变(所以集合的元素不能是列表),且不能重复,set中元素的排序和插入顺序无关,这一点和dict中的key的属性有点像,所以集合用的也是大括号,可以说是只有键没有值的字典
2、集合支持一些特有的操作,求交集&,并集|, 以及求差集-,请看例子
  1. >>> a = {1, 2, 3}
  2. >>> b = {1, 2, 4}
  3. >>> a & b
  4. {1, 2}
  5. >>> a | b
  6. {1, 2, 3, 4}
  7. >>> a - b
  8. {3}
  9. >>>
复制代码

这个问题的解决方法告诉我们字典的keys(), items()方法得到的可迭代对象(实际上它是一种视图)也支持集合的相关操作,这为我们解决问题提供了方便,比如 你想以现有字典构造一个排除几个指定键的新字典。你可以这么做
  1. >>> c = {key:a[key] for key in a.keys() - {'z', 'w'}}
  2. >>> c
  3. {'x': 1, 'y': 2}
复制代码
到这里有些鱼油会提出疑问,为什么values()方法不可以?答案是,字典的value值并不是唯一的,这一点不符合集合的特性,当然如果你想求两个字典相同的值有哪些,你可以将values()方法返回的可迭代对象用set()方法强行转化为集合再用&操作求出相同的值
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-5-16 02:20:25 | 显示全部楼层
花了两个多小时解决了pyqt那个俄罗斯方块代码中的bug,事实证明我还是太马虎了,三个错误都是由自己的输入失误造成的,下一步要实现界面和业务的逻辑分离,悲惨的发现Mr.R大神的那个pyqt5入门教程的网站上不去了,http://hi.baidu.com/lovebabycase,网上有好多转载的但是图都没有截好,还说从上面学一学界面和业务分离的做法,只能自己研究了,先睡觉了,困死~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-27 13:53

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表