Item 14: Prefer Exceptions to Returning None

Functions that returns None to indicate special meaning are error prone because None and other values (e.g., zero, the empty string) all evaluate to False in conditional expressions.

Raise exceptions to indicate special situations instead of returning None. Expect the calling code to handle exceptions properly when they're documented.

Item 15: Know How Closures Interact with Variable Scope

  1. # found never change
  2. def sort_priority(numbers, group):
  3. found = False
  4. def helper(x):
  5. if x in group:
  6. found = True
  7. return (0, x)
  8. return (1, x)
  9. numbers.sort(key=helper)
  10. return found
  11.  
  12. # use a mutable value, for example list
  13. def sort_priority(numbers, group):
  14. found = [False]
  15. def helper(x):
  16. if x in group:
  17. found[0] = True
  18. return (0, x)
  19. return (1, x)
  20. numbers.sort(key=helper)
  21. return found

Closure functions can refer to variables from any of the scopes in which they were defined.

By default, closures can't affect enclosing scopes by assigning variables.

In Python 2, use a mutable value (like a single-item list) to work around the lack of the nonlocal statement.

Avoid using nonlocal statements for anything beyond simple functions.

Item 16: Consider Generators Instead of Returning Lists

Using iterator can be clearer than the alternative of returning lists of accumulated results.

The iterator returned by a generator produces the set of values passed to yield expressions within the generator function's body.

Generators can produce a sequence of outputs for arbitrarily large inputs because their working memory doesn't include all inputs and outputs.

Item 17: Be Defensive When Iterating Over Arguments

The iterator protocol is how Python for loops and related expressions traverse the contents of a container type. When Python sees a statement like for x in foo it will actually call iter(foo). The iter built-in function calls the foo.__iter__ special method in turn. The __iter__ method must return an iterator object (which itself implements the __next__ special method). Then the for loop repeatedly calls the next built-in function on the iterator object until it's exhausted (and raises a StopIteration exception).

Practically speaking you can achieve all of this behavior for your classes by implementing the __iter__ method as a generator.

The protocol states that when an iterator is passed to the iter built-in function, iter will return the iterator itself. In contrast, when a container type is passed to iter, a new iterator object will be returned each time.

  1. >>> class MyContainer(object):
  2. ... def __iter__(self):
  3. ... return (_ for _ in xrange(5))
  4. ...
  5. >>> gen = MyContainer()
  6.  
  7. # a new iterator object will be returned each time
  8. >>> [_ for _ in gen]
  9. [0, 1, 2, 3, 4]
  10. >>> [_ for _ in gen]
  11. [0, 1, 2, 3, 4]
  12. >>> [_ for _ in gen]
  13. [0, 1, 2, 3, 4]
  14.  
  15. >>> iterator = (_ for _ in xrange(5))
  16.  
  17. # return the iterator itself
  18. >>> [_ for _ in iterator]
  19. [0, 1, 2, 3, 4]
  20. >>> [_ for _ in iterator]
  21. []
  22. >>> [_ for _ in iterator]
  23. []

Thus, you can test an input value for this behavior and raise a TypeError to reject iterators. It will work for any type of container that follows the iterator protocol.

  1. def normalize_defensive(numbers):
  2. if iter(numbers) is iter(numbers): # An iterator - bad!
  3. raise TypeError('Must supply a container')
  4. # sum will call ReadVisits.__iter__ to allocate a new iterator object
  5. total = sum(numbers)
  6. result = []
  7. # for loop will also call __iter__ to allocate a second iterator object
  8. for value in numbers:
  9. percent = 100 * value / total
  10. result.append(percent)
  11. return result
  1. >>> lst = [1,2,3]
  2. >>> iter(lst) == iter(lst)
  3. False
  4.  
  5. >>> gen = (_ for _ in xrange(4))
  6. >>> iter(gen) == iter(gen)
  7. True

Item 18: Reduce Visual Noise with Variable Positional Arguments

  1. >>> lst
  2. [1, 2, 3]
  3.  
  4. # join!
  5. >>> ','.join(str(x) for x in lst)
  6. '1,2,3'
  7. >>> ','.join([str(x) for x in lst])
  8. '1,2,3'
  9. >>> ','.join((str(x) for x in lst))
  10. '1,2,3'

Functions can accept a variable number of positional arguments by using *args in the def statement.

You can use the items from a sequence as the positional arguments for a function with the * operator.

Using the * operator with a generator may cause your program to run out of memory and crash.

Adding new positional parameters to functions that accept *args can introduce hard-to-find bugs.

Item 19: Provide Optional Behavior with Keyword Arguments

Function arguments can be specified by position or by keyword.

Keywords make it clear what the purpose of each argument is when it would be confusing with only positional arguments.

Keyword arguments with default values make it easy to add new behaviors to a function, especially when the function has existing callers.

Optional keyword arguments should always be passed by keyword instead of by position.

Item 20: Use None and Docstrings to Specify Dynamic Default Arguments

Default arguments are only evaluated once: during function definition at module load time. This can cause odd behaviors for dynamic values (like {} or []).

Use None as the default value for keyword arguments that have a dynamic value. Document the actual default behavior in the function's docstring.

Item 21: Enforce Clarity with Keyword-Only Arguments

  1. def safe_division_d(number, divisor, **kwargs):
  2. ignore_overflow = kwargs.pop('ignore_overflow', False)
  3. ignore_zero_div = kwargs.pop('ignore_zero_division', False)
  4. if kwargs:
  5. raise TypeError("Unexcepted **kwrags: %r" % kwargs)
  6. # ...
  7.  
  8. # raise Exception
  9. safe_division_d(1, 0, False, True)
  10.  
  11. >>>
  12. TypeError: safe_division_d() takes 2 positional arguments but 4 were given
  13.  
  14. # it works
  15. safe_division_d(1, 0, ignore_zero_division=True)

Keyword arguments make the intention of a function call more clear.

Use Keyword-only arguments to force callers to supply keyword arguments for potentially confusing functions, especially those that accept mutiple Boolean flags.

Python 2 can emulate keyword-only arguments for functions by using **kwargs and manually raising TypeError exceptions.

Effective Python2 读书笔记2的更多相关文章

  1. Effective Python2 读书笔记1

    Item 2: Follow the PEP 8 Style Guide Naming Naming functions, variables, attributes lowercase_unders ...

  2. Effective Python2 读书笔记3

    Item 22: Prefer Helper Classes Over Bookkeeping with Dictionaries and Tuples For example, say you wa ...

  3. Effective STL 读书笔记

    Effective STL 读书笔记 标签(空格分隔): 未分类 慎重选择容器类型 标准STL序列容器: vector.string.deque和list(双向列表). 标准STL管理容器: set. ...

  4. Effective STL读书笔记

    Effective STL 读书笔记 本篇文字用于总结在阅读<Effective STL>时的笔记心得,只记录书上描写的,但自己尚未熟练掌握的知识点,不记录通用.常识类的知识点. STL按 ...

  5. effective c++读书笔记(一)

    很早之前就听过这本书,找工作之前读一读.看了几页,个人感觉实在是生涩难懂,非常不符合中国人的思维方式.之前也有博主做过笔记,我来补充一些自己的理解. 我看有人记了笔记,还不错:http://www.3 ...

  6. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  7. Effective java读书笔记

    2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...

  8. Effective Objective-C 读书笔记

    一本不错的书,给出了52条建议来优化程序的性能,对初学者有不错的指导作用,但是对高级阶段的程序员可能帮助不是很大.这里贴出部分笔记: 第2条: 使用#improt导入头文件会把头文件的内容全部暴露到目 ...

  9. 【Effective C++读书笔记】序

    C++ 是一个难学易用的语言! [C++为什么难学?] C++的难学,不仅在其广博的语法,以及语法背后的语义,以及语义背后的深层思维,以及深层思维背后的对象模型: C++的难学还在于它提供了四种不同而 ...

随机推荐

  1. jquery富文本在线编辑器UEditor

    UEditor 是由百度「FEX前端研发团队」开发的所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码. UEditor的功能非常强大,官方 ...

  2. Vue2.0学习笔记一 :各种表达式

    #,过滤器 #,在Vue2.x中,过滤器只能在mustache绑定中使用,为了在指令帮定中实现同样的行为,你应该使用计算属性:     #,过滤器可以串联 {{ message | filterA | ...

  3. HTML5 File API — 让前端操作文件变的可能

    前言 在 HTML5 File API 出现之前,前端对于文件的操作是非常有局限性的,大多需要配合后端实现.出于安全角度考虑,从本地上传文件时,代码不可能获取文件在用户本地的地址,所以纯前端不可能完成 ...

  4. Ionic中使用Chart.js进行图表展示以及在iOS/Android中的性能差异

    Angular Chart 简介 在之前的文章中介绍了使用 Ionic 开发跨平台(iOS & Android)应用中遇到的一些问题的解决方案. 在更新0.1.3版本的过程中遇到了需要使用图表 ...

  5. 备忘:spring jdbc事务代码 mybatis, nhibernate

    http://files.cnblogs.com/files/mikelij/mymavenMar1.rar

  6. 匿名内部类与equals之学习要扎实

    匿名内部类是胡哥给我上的第一节课,他一直在不断强调着“逻辑与思维”的重要性, 遇到问题不能用“不知道和没学过”去逃避它,所有的不知道和没教过都源自于没见过,一定要学会去看源代码,不要人云亦云..... ...

  7. 【jQuery】scroll 滚动到顶部

    Jquery 实现页面滚动到顶端 $(document).ready(function () { // 滚动窗口来判断按钮显示或隐藏 $(window).scroll(function () { // ...

  8. [转]Tomcat启动java.lang.OutOfMemoryError: PermGen space错误解决

    原文地址:http://outofmemory.cn/java/OutOfMemoryError/outofmemoryerror-permgen-space-in-tomcat-with-eclip ...

  9. java高新技术-java5的静态导入与编译器语法设置

    静态导入 import语句可以导入一个类或某个包中的所有类 import static 语句导入有一个类中的某个静态方法或所有静态方法 使用Math.random() 可以这样做 package co ...

  10. Ubuntu操作系统相关

    1.安装 三种网络类型 修改密码 重启unbuntu系统,出现starting启动界面后,长按shift键. 出现如下引导界面: (注意:这里保持默认的选项就行,即白色横条选择在*Ubuntu上,不要 ...