Code Monkey home page Code Monkey logo

one-python-craftsman's Introduction

《Python 工匠》图书首页上线啦!共有 3 章在线内容,欢迎阅读。

图书《Python 工匠:案例、技巧与工程实践》现已正式上市。同开源文章相比,图书的知识结构更为流畅,增加了“函数”“面向对象编程”等核心章节,总内容量几乎翻倍,欢迎购买。

点击购买 | 豆瓣书评 | 图灵社区


『Python 工匠』是什么?

我一直觉得编程某种意义上是一门『手艺』,因为优雅而高效的代码,就如同完美的手工艺品一样让人赏心悦目。

在雕琢代码的过程中,有大工程:比如应该用什么架构、哪种设计模式。也有更多的小细节,比如何时使用异常(Exceptions)、或怎么给变量起名。那些真正优秀的代码,正是由无数优秀的细节造就的。

『Python 工匠』这个系列文章,是我的一次小小尝试。它专注于分享 Python 编程中的一些偏 『小』 的东西。希望能够帮到每一位编程路上的匠人。

文章列表

如果你觉得读 GitHub 文件不太方便,也可以访问这个镜像站点阅读所有文章(由 @pengzhangzhi 搭建)。

也欢迎你关注我的微信公众号:piglei,在第一时间阅读最新文章:

所有文章禁止转载,如需转载请通过微信公众号联系我。

详细内容

  • 如何为变量起名
    • 1 - 变量名要有描述性,不能太宽泛
    • 2 - 变量名最好让人能猜出类型
      • 『什么样的名字会被当成 bool 类型?』
      • 『什么样的名字会被当成 int/float 类型?』
      • 其他类型
    • 3 - 适当使用『匈牙利命名法』
    • 4 - 变量名尽量短,但是绝对不要太短
      • 使用短名字的例外情况
    • 5 - 其他注意事项
  • 更好的使用变量
    • 1 - 保持一致性
    • 2 - 尽量不要用 globals()/locals()
    • 3 - 变量定义尽量靠近使用
    • 4 - 合理使用 namedtuple/dict 来让函数返回多个值
    • 5 - 控制单个函数内的变量数量
    • 6 - 及时删掉那些没用的变量
    • 7 - 能不定义变量就不定义
  • 结语
  • 最佳实践
    • 1 - 避免多层分支嵌套
    • 2 - 封装那些过于复杂的逻辑判断
    • 3 - 留意不同分支下的重复代码
    • 4 - 谨慎使用三元表达式
  • 常见技巧
    • 1 - 使用“德摩根定律”
    • 2 - 自定义对象的“布尔真假”
    • 3 - 在条件判断中使用 all() / any()
    • 4 - 使用 try/while/for 中 else 分支
  • 常见陷阱
    • 1 - 与 None 值的比较
    • 2 - 留意 and 和 or 的运算优先级
  • 结语
  • 注解
  • 最佳实践
    • 1 - 少写数字字面量
      • 使用 enum 枚举类型改善代码
    • 2 - 别在裸字符串处理上走太远
    • 3 - 不必预计算字面量表达式
  • 实用技巧
    • 1 - 布尔值其实也是“数字”
    • 2 - 改善超长字符串的可读性
      • 当多级缩进里出现多行字符串时
    • 3 - 别忘了那些 “r” 开头的内建字符串函数
    • 4 - 使用“无穷大” float("inf")
  • 常见误区
    • 1 - “value += 1” 并非线程安全
    • 2 - 字符串拼接并不慢
  • 结语
  • 底层看容器
    • 写更快的代码
      • 1 - 避免频繁扩充列表/创建新列表
      • 2 - 在列表头部操作多的场景使用 deque 模块
      • 3 - 使用集合/字典来判断成员是否存在
  • 高层看容器
    • 写扩展性更好的代码
      • 面向容器接口编程
  • 常用技巧
    • 1 - 使用元组改善分支代码
    • 2 - 在更多地方使用动态解包
    • 3 - 使用 next() 函数
    • 4 - 使用有序字典来去重
  • 常见误区
    • 1 - 当心那些已经枯竭的迭代器
    • 2 - 别在循环体内修改被迭代对象
  • 总结
  • 系列其他文章
  • 注解
  • 编程建议
    • 1 - 单个函数不要返回多种类型
    • 2 - 使用 partial 构造新函数
    • 3 - 抛出异常,而不是返回结果与错误
    • 4 - 谨慎使用 None 返回值
      • 1 - 作为操作类函数的默认返回值
      • 2 - 作为某些“意料之中”的可能没有的值
      • 3 - 作为调用失败时代表“错误结果”的值
    • 5 - 合理使用“空对象模式”
    • 6 - 使用生成器函数代替返回列表
    • 7 - 限制递归的使用
  • 总结
  • 附录
  • 前言
  • 三个好习惯
    • 1 - 只做最精确的异常捕获
    • 2 - 别让异常破坏抽象一致性
    • 3 - 异常处理不应该喧宾夺主
  • 总结
  • 附录
  • 前言
  • 什么是“地道”的循环?
    • enumerate() 所代表的编程思路
  • 建议1:使用函数修饰被迭代对象来优化循环
    • 1 - 使用 product 扁平化多层嵌套循环
    • 2 - 使用 islice 实现循环内隔行处理
    • 3 - 使用 takewhile 替代 break 语句
    • 4 - 使用生成器编写自己的修饰函数
  • 建议2:按职责拆解循环体内复杂代码块
    • 复杂循环体如何应对新需求
    • 使用生成器函数解耦循环体
  • 总结
  • 附录
  • 前言
  • 最佳实践
    • 1 - 尝试用类来实现装饰器
    • 2 - 使用 wrapt 模块编写更扁平的装饰器
  • 常见错误
    • 1 - “装饰器”并不是“装饰器模式”
    • 2 - 记得用 functools.wraps() 装饰内层函数
    • 3 - 修改外层变量时记得使用 nonlocal
  • 总结
  • 附录
  • 前言
  • 一个关于模块的小故事
    • 需求变更
    • 解决环形依赖问题
    • 小 C 的疑问
  • 总结
  • 附录
  • 前言
    • Python 里的规则
  • 案例:从两份旅游数据中获取人员名单
    • 第一次蛮力尝试
    • 尝试使用集合优化函数
    • 对问题的重新思考
    • 利用集合的游戏规则
    • 使用 dataclass 简化代码
    • 案例总结
  • 其他规则如何影响我们
    • 使用 __format__ 做对象字符串格式化
    • 使用 __getitem__ 定义对象切片操作
  • 总结
  • 附录
  • 前言
  • 建议一:使用 pathlib 模块
    • 使用 pathlib 模块改写代码
    • 其他用法
  • 建议二:掌握如何流式读取大文件
    • 标准做法的缺点
    • 使用 read 方法分块读取
    • 利用生成器解耦代码
  • 建议三:设计接受文件对象的函数
    • 如何编写兼容二者的函数
  • 总结
  • 附录
  • 注解
  • 前言
    • Python 对 OOP 的支持
    • SOLID 设计原则
  • SOLID 原则与 Python
  • S:单一职责原则
    • 违反“单一职责原则”的坏处
    • 拆分大类为多个小类
    • 另一种方案:使用函数
  • O:开放-关闭原则
    • 如何违反“开放-关闭原则”
    • 使用类继承来改造代码
    • 使用组合与依赖注入来改造代码
    • 使用数据驱动**来改造代码
  • 总结
  • 附录
  • 前言
  • 里氏替换原则与继承
  • L:里氏替换原则
  • 一个违反 L 原则的样例
    • 不当继承关系如何违反 L 原则
    • 一个简单但错误的解决办法
    • 正确的修改办法
  • 另一种违反方式:子类修改方法返回值法返回值)
    • 分析类方法返回结果
    • 如何修改代码
    • 方法参数与 L 原则
  • 总结
  • 附录
  • 前言
  • D:依赖倒置原则
    • 需求:按域名分组统计 HN 新闻数量
    • 为 SiteSourceGrouper 编写单元测试
      • 使用 mock 模块
    • 实现依赖倒置原则
    • 依赖倒置后的单元测试
    • 问题:一定要使用抽象类 abc 吗?
    • 问题:抽象一定是好东西吗?
  • I:接口隔离原则
    • 例子:开发页面归档功能
    • 问题:实体类不符合 HNWebPage 接口规范
    • 成功违反 I 协议
    • 如何分拆接口
    • 一些不容易发现的违反情况
    • 现实世界中的接口隔离
  • 总结
  • 附录
  • 前言
  • 第一课:使用分支还是异常?
    • 获取原谅比许可简单(EAFP)
  • 当容器内容不存在时
    • 使用 defaultdict 改写示例
    • 使用 setdefault 取值并修改
    • 使用 dict.pop 删除不存在的键
    • 当列表切片越界时
  • 好用又危险的 “or” 操作符
  • 不要手动去做数据校验
  • 不要忘记做数学计算
  • 总结
  • 附录
  • 表达式的特点
  • 海象操作符
      1. 用于分支语句
      1. 消除推导式中的重复
      1. 捕获推导式的中间结果
      1. 赋值表达式的限制
  • 其他建议
      1. “更紧凑”不等于“更好”
      1. 宜少不宜多

one-python-craftsman's People

Contributors

0x0400 avatar bekindtoyourself avatar brucelee569 avatar catbaron0 avatar clarksun avatar cwjokaka avatar dreagonmon avatar hjlarry avatar hylarucoder avatar jasonnor avatar kmvan avatar laixintao avatar lizhutou avatar lordmoma avatar luliangce avatar miniyk2012 avatar mosesfu avatar mrlyc avatar piglei avatar tingshuo123 avatar wgzhao avatar yangzhenzhao avatar yaowenqiang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

one-python-craftsman's Issues

err_msg未定义?

class CreateItemError(Exception):
"""创建 Item 失败时抛出的异常"""

def create_item(name):
"""创建一个新的 Item

:raises: 当无法创建时抛出 CreateItemError
"""
if len(name) > MAX_LENGTH_OF_NAME:
    raise CreateItemError('name of item is too long')
if len(CURRENT_ITEMS) > MAX_ITEMS_QUOTA:
    raise CreateItemError('items is full')
return Item(name=name)

def create_for_input():
name = input()
try:
item = create_item(name)
except CreateItemError as e:
print(f'create item failed: {err_msg}') #这句是不是有bug,err_msg 无定义
else:
print(f'item<{name}> created')

OOP 原则

不是 issue, 只是 comment.

里式替换的另一个比较隐蔽的错误会发生在多层抽象的耦合里.

比如有两个抽象 A 和 B, 类型声明是 A 以 B 作为入参 A(B), 但是如果实际的实现里出现了类型特定化, 那么说明这里的抽象失败了.
具体来讲, 抽象 A 有两个实现 A1, A2; 抽象 B 也有两个实现 B1, B2; 一个符合里式替换的实现应该允许 A1(B1), A1(B2), A2(B1), A2(B2) 这些调用组合, 但是稍微缺少经验的工程师可能会实现为特定类型的入参, 只能运行 A1(B1), A2(B2), 传入不正确的类型就会报错.
这类问题在使用抽象工厂的时候特别常见, 因为抽象工厂里就有多个抽象的多个实现, 一旦业务把多个抽象耦合起来, 就容易违反里式替换.
抽象工厂的 UML 就有 A1 A2 B1 B2:
image


依赖倒置其实和开放封闭是有关的, 应该说依赖倒置就是为了开放封闭.

拿你的例子来说:
image
如果未来需要实现另一种 HNWebPage, 比如叫做 LocalHNWebPage, 没有依赖倒置的话, 业务逻辑代码里 (SiteSourceGrouper) 就要去修改 import 模块, 这就违反了开放封闭, 因为并没有修改业务逻辑, 却要改业务代码; 而使用依赖倒置就完美地开放封闭了.
实际上 Django ORM 就是这样的, 想象一下 view 层里的 import model, 这个 model 其实只是一个抽象, 这样将来就算更换下层数据库的实现 (从 MySQL 换成 PostgreSQL), view 层代码(理论上)不需要做相应更改, 这就是依赖倒置这层抽象带来的好处.

写的很棒

写得太棒了,看了以后感觉以前写的代码太烂了,出了实体书一定支持。

is 和 ==的使用

最佳实践的第二小节别在字符串上走太远,改进后的代码中使用了 !=None ,虽然在这里没有什么大问题,但是既然主题是匠心,还是忍不住说了,😂。另外,对于字符串的比较是用is还是==想听听大神的意见。PS,我明白is和==的区别,却不是很明白该怎么更精确的选择使用,就比如这里的!=None也没有什么问题,想听听关于字符串,甚至内置其他内置数据类型的比较是用is还是==的一个详细解释

代码没有高亮

Python 工匠:写好面向对象代码的原则(中)
中的一段代码没有高亮 忘写python了,这算Bug吗?还是feature.

原文:

现在,假设我需要写一个函数,来获取和用户有关的所有帖子标题:

def list_user_post_titles(user: User) -> Iterable[str]:
    """获取与用户有关的所有帖子标题
    """
    for post_id in user.list_related_posts():
        yield session.query(Post).get(post_id).title

关于「使用 try/while/for 中 else 分支」

while ... else 和 for ... else 相当的反直觉,引用 Effective Python 中的例子(加了一些注释):

# 看上去 else 是「之前」没有运行才会运行的,实际上之前 for loop 完成之后还是运行了 else
for i in range(3):
  print(i)
else:
  print("ELSE!")      # 可及


# 看上去 for loop 退出了,应该运行 else 了,实际上 else 会被跳过
for i in range(3):
  print(i)
  if i == 1:
    break       # 注意这里的 break
else:
  print("ELSE!")      # 不可及
  

# for loop 是空的时候 直接执行 else
for i in []:
  print(i)
else:
  print("ELSE!")       # 可及


# while 初始条件是 False 时直接执行 else
while False:
    print("ok")
else:
    print("ELSE")      # 可及


a = iter([None, 1, 2, 3, None, 5, 6])
while next(a):
    print('hi')
else:
    print("ELSE")     # 可及

这里也有一些讨论:https://mail.python.org/pipermail/python-ideas/2009-October/006155.html

空对象模式 和 None

在第五章中,您讨论了函数返回值的问题。

在「谨慎使用 None 返回值」的讨论中提到我们应该思考「函数签名(名称与参数)与 None 返回值之间是否存在一种“意料之中”的暗示」。在类似 create_user_from_name() 的函数中,用户预期是能拿到一个结果的。

但在 「空对象模式」中,却手动创造了一个 NullAccount 类,来作为 Account.from_string() 的返回值。在我看来,这难道不是矛盾的建议么?

首先,从 from_string() 的名称与参数,用户应该预期会拿到一个 account,如果按照上文的建议,如果输入字符串非法,应该直接抛出异常。
其次,如果在这里由于某种原因我们选择返回一个 NullAccount 来代替把异常抛给用户,为什么我们不让 Account.from_string() 在处理异常时直接返回空的 usernamebalance

设计模式

你好,下一篇能否介绍一下python中常用到的设计模式呢,因为要构建高效的python代码,和适用合理的设计模式也分不开吧。

感谢

非常好的总结和分享
感谢感谢

勘误

https://github.com/piglei/one-python-craftsman/blob/master/zh_CN/2-if-else-block-secrets.md

`上面的代码里,判断 UserCollection 是否有内容时用到了 users._users 的长度。其实,通过为 UserCollection 添加 len 魔法方法,上面的分支可以变得更简单:

class UserCollection:

def __init__(self, users):
    self._users = users

def __len__(self):
    return len(self._users)

users = UserCollection([piglei, raymond])

定义了 len 方法后,UserCollection 对象本身就可以被用于布尔判断了

if users:
print("There's some users in collection!")
`

应该是 if len(users):

+=和join效率的问题

在处理长度为4201612的字符串时
+=用了91.966637s
join用了10.327656s
虽然上面的情况比较极端,我觉得还是尽量用join更好一些

环境是OS X 10.14.5 Python3.7

催更

文章写的真好,获益匪浅。
感觉这个系列文章可以出一本书了~
另外问一下 写好面向对象代码的原则(下)什么时候更新
^ ^

错了几个字

def enter(self):
# 刚方法将在进入上下文时调用
return self

该方法将在进入上下文时调用 错了个字

还有前面几节举的例子, 列表的命名用 'l'(小写字母l), 看了半天, 觉得不应该啊..... 哈哈

推荐添加用在装饰器上的自省函数 inspect.signature 的使用说明

inspect.signature 可以用来查看内层(被装饰的)函数的参数,提前检查传入外层函数传入的参数是否正确,还可以方便地访问特定参数。

import sys
import inspect
import functools
import traceback


def decorator(func):
    sig = inspect.signature(func)

    @functools.wraps(func)
    def wrap(*args, **kwargs):
        bound_arguments = sig.bind(*args, **kwargs)
        bound_arguments.apply_defaults()
        print(bound_arguments.arguments)
        return func(*args, **kwargs)

    return wrap


@decorator
def boo(a, b, c):
    pass

boo(1, b=2, c=3)

try:
    boo(1, b=2, c=3, d=4)
except TypeError:
    traceback.print_exc(file=sys.stdout)

执行结果

{'a': 1, 'b': 2, 'c': 3}
Traceback (most recent call last):
  File "<ipython-input-1-b43513683a33>", line 27, in <module>
    boo(1, b=2, c=3, d=4)
  File "<ipython-input-1-b43513683a33>", line 12, in wrap
    bound_arguments = sig.bind(*args, **kwargs)
  File "/usr/local/Cellar/[email protected]/3.9.1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/inspect.py", line 3062, in bind
    return self._bind(args, kwargs)
  File "/usr/local/Cellar/[email protected]/3.9.1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/inspect.py", line 3051, in _bind
    raise TypeError(
TypeError: got an unexpected keyword argument 'd'

编写抽象类的目的

感谢您写的这些文章,读后获益良多!

在阅读写好面向对象代码的原则(上) 这篇文章里,有一个hint:“定义抽象类在 Python 的 OOP 中并不是必须的,你也可以不定义它” 。我想知道,既然不是必须的,那定义编写抽象类的目的是什么?它有什么作用?

next() 函数提高性能的疑惑

Hi @piglei , 您的系列文章让人收益匪浅。

读到第四章“容器的门道”,对 next() 可以高效的实现 “从列表中查找第一个满足条件的成员”,我自己测了一下性能,似乎还不如普通方法。

In [2]: numbers = [3, 7, 8, 2, 21]

In [3]: %timeit [i for i in numbers if i % 2 == 0][0]
445 ns ± 5.35 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [4]: %timeit [i for i in numbers if i % 2 == 0][0]
449 ns ± 5.75 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [5]: %timeit next((i for i in numbers if i % 2 == 0))
501 ns ± 10.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [6]: %timeit next((i for i in numbers if i % 2 == 0))
500 ns ± 4.05 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

使用namedtuple可以用解包赋值给多个变量

不过这样做也有坏处,因为代码对变更的兼容性虽然变好了,但是你不能继续用之前 x, y = f() 的方式一次解包定义多个变量了。取舍在于你自己。
这句话不妥,使用namedtuple可以这么做

Python suffixed of some code block is missing

您好,很棒的一系列文章!阅读过程发现个小问题,该文章的此处:

https://github.com/piglei/one-python-craftsman/blob/master/zh_CN/3-tips-on-numbers-and-strings.md

但是这样写会破坏整段代码的缩进视觉效果,显得非常突兀。要改善它有很多种办法,比如我们可以把这段多行字符串作为变量提取到模块的最外层。不过,如果在你的代码逻辑里更适合用字面量的话,你也可以用标准库 textwrap 来解决这个问题:

from textwrap import dedent

def main():
    if user.is_active:
        # dedent 将会缩进掉整段文字最左边的空字符串
        message = dedent("""\
            Welcome, today's movie list:
            - Jaw (1975)
            - The Shining (1980)
            - Saw (2004)""")

Code block 上少了 python suffixed:

from textwrap import dedent

def main():
    if user.is_active:
        # dedent 将会缩进掉整段文字最左边的空字符串
        message = dedent("""\
            Welcome, today's movie list:
            - Jaw (1975)
            - The Shining (1980)
            - Saw (2004)""")

如果不介意,我可以发个PR协助修正

第六篇-上下文管理器改善异常处理流程的疑问

class raise_api_error:
    """captures specified exception and raise ApiErrorCode instead

    :raises: AttributeError if code_name is not valid
    """
    def __init__(self, captures, code_name):
        self.captures = captures
        self.code = getattr(error_codes, code_name)

    def __enter__(self):
        # 该方法将在进入上下文时调用
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        # 该方法将在退出上下文时调用
        # exc_type, exc_val, exc_tb 分别表示该上下文内抛出的
        # 异常类型、异常值、错误栈
        if exc_type is None:
            return False

        if exc_type == self.captures:
            raise self.code from exc_val
        return False

这里的 raise self.code from exc_val 是啥意思?from exc_val 没看懂。

书籍建议

建议代码清单8-7和8-8中,使用functools.update_wrapper替换update_wrapper
一个是因为文章中并没有说update_wrapper是functools中的,还有就是8-8的代码中有用到functools.partial,应当统一

improvement:优化阅读体验

建议在每一篇文章的最后添加两个跳转链接,分别是:

  • 【前一篇文章】
  • 【后一篇文章】

能有效提升连续阅读体验。

关于EP13的一点小小的建议

例子的代码这么写是不是会更舒服?因为感觉上判断修改应该是类内部的逻辑。

class User(Model):
    """普通用户模型类
    """
    def __init__(self, username: str):
        self.username = username

    def allow_deactivate(self) -> bool:
        """是否允许被停用
        """
        return True

    def _deactivate(self):
        """将当前用户停用
        """
        self.is_active = True
        self.save()

    def deactivate(self) -> bool:
        """将当前用户停用
        """
        if self.allow_deactivate():
            self._deactivate()
            return True
        else:
            return False

class Admin(User):
    """管理员用户类
    """
    def allow_deactivate(self) -> bool:
        # 管理员用户不允许被停用
        return False

def deactivate_users(users: Iterable[User]):
    """批量停用多个用户
    """
    for user in users:
        is_deactivated = user.deactivate()
        if not is_deactivated:
            logger.info(f'user {user.username} does not allow deactivating, skip.')

另外,停用之后is_active变成了True,是不是反了?

让class变得可调用?

函数自然是“可被调用”的对象。但除了函数外,我们也可以让任何一个类(class)变得“可被调用”(callable)。办法很简单,只要自定义类的 call 魔法方法即可。

类一直是可被调用的“callable”,这里是不是写错了,应该是object吧

2.编写条件分支代码的技巧

if user.no_profile_exists:
    +++ profile_func = create_user_profile
    extra_args = {'points': 0, 'created': now()}
else:
    +++ profile_func = update_user_profile
    extra_args = {'updated': now()}

profile_func(
    username=user.username,
    email=user.email,
    age=user.age,
    address=user.address,
    **extra_args
)

你好,上面代码中我标记了 “+++” 的两行可以改成下面这样的吗?

create_user_profile = profile_func
update_user_profile = profile_func

对于with嵌套如何优化

感谢作者的分享,优美的文笔,恰当的例子,让我觉得我以前写的不是python。

对于with嵌套作者有没有好的优化思路?写代码的时候遇到要打开多个文件,嵌套好几层with获取 文件对象,感觉很丑。

静态类型注释

静态类型注释是不是改变了变量名定义的方式和需求?

链接文本错误

/zh_CN/4-mastering-container-types.md
底部的:
<<<上一篇【3.编写条件分支代码的技巧】
指向正确,名字错误,应该是:
<<<上一篇【3.使用数字与字符串的技巧】

“不必预计算字面量表达式“的疑问

Python 代码在执行时会被解释器编译成字节码,而真相就藏在字节码里。让我们用 dis 模块看看:

def f1(delta_seconds):
    if delta_seconds < 11 * 24 * 3600:
        return

import dis
dis.dis(f1)

# dis 执行结果
  5           0 LOAD_FAST                0 (delta_seconds)
              2 LOAD_CONST               1 (950400)
              4 COMPARE_OP               0 (<)
              6 POP_JUMP_IF_FALSE       12

  6           8 LOAD_CONST               0 (None)
             10 RETURN_VALUE
        >>   12 LOAD_CONST               0 (None)
             14 RETURN_VALUE

看见上面的 2 LOAD_CONST 1 (950400) 了吗?这表示 Python 解释器在将源码编译成成字节码时,会计算 11 * 24 * 3600 这段整型字面量,并用 950400 替换它。

所以,当我们的代码中需要出现复杂计算的字面量时,请保留整个算式吧。它对性能没有任何影响,而且会增加代码的可读性。

就算字节码会用计算好的结果替换“11 * 24 * 3600”,后面反复执行代码会用优化过的字节码;
但第一次源码编译成字节码时还是会计算“11 * 24 * 3600”的,这一次的速度还是会比直接写“950400”慢呀~

縮進問題

在 做一个精通规则的玩家 這一節裏 的 利用集合的游戏规则這一小節 定義了VisitRecord 這個類,下面的__hash__ 和__eq__兩個方法爲了是不是該有縮進,來匹配前文的語法結構

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.