Code Like a Pythonista: Idiomatic Python


如果你有C++基础,那学习另一门语言会相对容易。因为C++即面向过程,又面向对象。它很底层,能像C一样访问机器;它也很高级,有模板、STL
等。如果认真读过《深入C++对象模型》,我想其它语言不会比这个更复杂。你对C++了解的越深,你用其它语言写出的代码就越像C++,这样就体现不出新
语言的价值了。所以,学习新语言要抛弃原有的潜意识,包括代码风格。

1. The Zen of Python (1)

漂亮比丑陋好
         清晰比隐含好
         简单比复杂好
         复杂比晦涩好
         平摊比嵌套好
         松耦合比紧耦合好
         可读性是有价值的
         特殊的条件不足以打破这些条款
         尽管实践打败理论的纯洁
         错误永远不要掩盖
         除非明确地平息它
         ……

2. PEP 8: Style Guide for Python

关于Python的重要风格准则

Whitespace1

  • 每级对齐为4个空格
  • 没有硬tab
  • 永远不要把tab与空格混用
  • 函数之间留出1行空白
  • 类之间留出2行空白

Whitespace 2

  • 在字典,列表,元组,参数列表的”,”后面加上空格,字典中”:”后也加上空格
  • 在赋值或比较符间加上空格
  • 在括号中要紧挨空格,函数名与括号也不要有空格
  • 在docstrings中不要立即空格

Naming

  • joined_lower用于函数,方法,属性
  • joined_lower或ALL_CAPS用于常量
  • StudlyCaps用于类, 不需要前面加C
  • #每字母大写
  • camelCase仅用于兼容已存在的惯例
  • 属性有:interface,_internal, __private。但后一种绝对不要使用。

一些来自C++/Java对类的访问权限过于在意。在Python中,MyClass.__private会直接解析为
MyClass._MyClass__private,因为它可以造成“视觉上”的不可访问。Python有条原则是:“we’reall
consenting adults
here”,你没有理由向我隐藏什么。子类有权力从父类继承属性,而父类有义务向子类提供相关文档来帮助其重写,而非拒绝。

Python倡导使用_internal来表示私有属性,它没有命令空间限制,而仅仅是善意提醒“be careful with this,
it's an internalimplementation detail; don't touch it if you don't fully understand it”

Long Lines &Continuations

在括号里的换行使用隐含换行,但要注意对齐

def __init__(self, first, second, third,
fourth, fifth, sixth):
output = (first + second + third
+ fourth + fifth + sixth)

其它换行要使用“\”,注意后面千万不要有空格

LongStrings

与C语言一样,两个相邻的字符串是可以被编译器自动连接的。有一点不同的是,C语言中字符串只有一种形式,即用””,但Python中可以有’’,””,r’’,’’’,”””等等。不过原理都是一样的。

组合语句

Python中不提倡将多条语句写在同一行。比如if语句等。Python是非常讲究通过缩进来显示代码的结构与流程。

交换值

Python中的元组是非常有意思且不被C语言系的人所察觉。

b, a = a, b

元组有非常好的通用性,列表与元组可以很容易地交换

a = [12, 34, 45]
b, c, d = a

元组还常常用在for语句中,用于一次处理多个索引

>>> people = [l, ['Guido', 'BDFL', 'unlisted']]
>>> for (name, title, phone) in people:
...     print name, phone

More About Tuples

Tuples的构造最重要的是“,”.比如、

>>> 1,
(1,)

即使上面没有括号也无妨。

Interactive “_”

在解释器中,_用于表示上次运算的结果。这种机制往往会给使用都很大的方便!

Building String from Substrings、、

这一条在Python世界中应该是很普及了。’’.join()只有在替代for循环连接列表时才有用

colors = ['red', 'blue', 'green', 'yellow']
result = ''
for s in colors:
    result += s

result = ''.join(colors) #这一条要比上面for循环更有效率

Used in where possible

首先,in是操作符而不是关键字;其次,所有的内建窗口都支持此操作符。作者要强调的是,in有两个常用的位置:1. 配合for执行遍历;2. 与if一起使用判断存在。

作者一再强调,字典重载的in操作是对象是所有的keys,所以没必要先调用d.keys()获取键的列表,再使用in,而是直接用in d就可以了!

Dictionary get Method

在向字典中添加key时,常常要判断原来的key是否存在。如果仅仅是对原来的值做一些操作,那么get方法就非常适合。

get(key,default):获取key的值,如果key不存在,则返回default。

Dictionary setdefault Method

上一节是获取,那么相应的会有设置。setdefault的语义是”set if necessary, the get”,首先会判断key是否存在,如果不存在则设置值,否则返回已存在的值。在cookbook一书中,它提到这一函数对于值为链表的字典很有用。

defaultdict

它是从字典中派生出来的,顾名思义,这种字典有一个默认的值(事实上它通过一个函数)。这个种字典的产生来源于简化setdefault的调用,在以后遇到使用setdefault时,可以考虑使用这个特化的字典代替。

PS:这个类来源于collections模块,这个模块还包含其它有用模块,包括队列、OrdereDict、MutableSet等。

Building Dictionary

将2个序列组合在字典:一个序列为键,别一个为值。这种操作有一个惯用法,即使用zip组合。

given = ['John', 'Eric', 'Terry', 'Michael']
family = ['Cleese', 'Idle', 'Gilliam', 'Palin']
pythons = dict(zip(given, family))

Test for Truth Values

Python中不喜欢在条件判断时与True或False做比较,而是直接用内置转换和not来判断。这样做代码更简练。下面是判断True与False的完整表格。

False

True

False (== 0)

True (== 1)

"" (empty string)

any string but "" (" ", "anything")

0, 0.0

any number but 0 (1, 0.1, -1, 3.14)

[], (), {}, set()

any non-empty container ([0], (None,), [''])

None

almost any object that's not explicitly False

Index & Item:enumerate

enumerate函数很大的特点是这是个generator函数,所以在一些场合效率会不错。在涉及Index时,这个函数应该是用得最多的。因为
Python语言中for循环的天生缺陷,如果要达到这个效果,必须用range,并再配合索引。正因为这个缺陷,才有了这个函数产生!这给我的感觉就像
STL很多人推荐用迭代器遍历,有人觉得声明太冗长,于是在C++0x推出一个auto关键字来。

Default Parameter Values

一开始出现了一个非常令人不解的代码

def bad_append(new_item, a_list=[]):
    a_list.append(new_item)
    return a_list
>>> print bad_append('one')
['one']
>>> print bad_append('two')
['one', 'two']

问题原因是,a_list是一个变量,它在声明的时候被定义为一个空的list。而list是mutable对象~~~~~~~~~~

最终我找到它的原因。在函数声明时,创建了一个空的list (‘[]’),a_list只不过是这个空list的Label而已。在编译器中,a_list被定死为某一全局list的地址“引用”。在第一次调用 append(‘on’)时,那个空list变成了[‘one’],函数退出后此list没有回收,所以在下一次调用时才会出现这种情况!

Advanced % String Formatting

%有一个非常有意思的用法,即在字符串内写出对象名字。

values = {'name': name, 'messages': messages}
print ('Hello %(name)s, you have %(messages)i ' % values)

这种写法的好处是,当要改变打印格式时,只需要改变里面的内容即可。通常,values是用locals()代替,这样一来这种灵活的机制就非常厉害了。例如,可以向某一函数传入一条字符串就可以指定打印的内容了。

Generator Expression(生成器表达式)

GE与listcomprehension(列表解析)非常类似

列表解析:
语法:[expr for iter_var in iterable] 或 [expr for iter_var in iterable ifcond_expr]

生成器表达式:
语法:(expr for iter_var in iterable) 或 (expr for iter_var in iterable if cond_expr)

生成器表达式比列表解析晚一点出来,它的好处非常明显,就是它返回的是一个“生成器”,而非一个列表。

生成器在Python中被推荐替代常规的for循环,而很多地方生列表施展的地方成器也可以替代,因为本质上它们支持程度相同。当列表仅仅是作为临时使用时,生成器可能在内存上表现更佳。

Reading Lines From Text/Data File

请看代码

datafile = open('datafile')
for line in datafile:
    do_something(line)

可能不少人会使用readlines方法,对于小文件,两者没有区别,但是大文件前者效率会高很多。

Python——Code Like a Pythonista: Idiomatic Python的更多相关文章

  1. 《Writing Idiomatic Python》前两部分的中文翻译

    汇总了一下这本小书前两部分的内容: 翻译<Writing Idiomatic Python>(一):if语句.for循环 翻译<Writing Idiomatic Python> ...

  2. 翻译《Writing Idiomatic Python》(五):类、上下文管理器、生成器

    原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...

  3. 翻译《Writing Idiomatic Python》(一):if语句、for循环

    开篇废话 这是在美国Amazon上评价很不错的一本书,其实严格来说这可能不算书,而是一本小册子.就像书名一样,里面的内容主要是用一些例子讲述地道的Python的代码是怎样写的.书中把很多例子用不良风格 ...

  4. 翻译《Writing Idiomatic Python》(二):函数、异常

    原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...

  5. 翻译《Writing Idiomatic Python》(四):字典、集合、元组

    原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...

  6. 翻译《Writing Idiomatic Python》(三):变量、字符串、列表

    原书参考:http://www.jeffknupp.com/blog/2012/10/04/writing-idiomatic-python/ 上一篇:翻译<Writing Idiomatic ...

  7. 分享书籍[writing idiomatic python ebook]

    你是不是总是觉得学了python好久,蓦然回首,总是感觉写的代码不是那么有pythonic的味道.看看别人的代码(django,webpy),再看看自己的代码,觉得就是一java-python的混合体 ...

  8. Exploring Python Code Objects

    Exploring Python Code Objects https://late.am/post/2012/03/26/exploring-python-code-objects.html Ins ...

  9. 机器学习算法实现(R&Python code)

    Machine Learning Algorithms Machine Learning Algorithms (Python and R) 明天考试,今天就来简单写写机器学习的算法 Types Su ...

随机推荐

  1. Java 原子性引用 AtomicReference

    http://www.jianshu.com/p/882d0e2c3ea6 实现 原子操作 使用场景: 一个线程使用student对象,另一个线程负责定时读表,更新这个对象.那么就可以用AtomicR ...

  2. Windows+Ubuntu双系统如何设置Windows为第一启动项

    在安装双系统的时候,如果先安装的是Windows然后再安装Ubuntu系统,开机时是以Ubuntu的grub来引导Windows的,而且默认进入Ubuntu系统,下面我们介绍如何更改这个默认项,然后让 ...

  3. php 单文件上传

    php 单文件上传 通过 PHP,可以把文件上传到服务器. 创建一个文件上传表单 允许用户从表单上传文件是非常有用的. 请看下面这个供上传文件的 HTML 表单: Filename: 请留意如下有关此 ...

  4. 最近项目中用到的js

    1.用字典判断数组是否有重复function ticketTypeValidate() { var ticketArr = []; var tickettype = $("div[name= ...

  5. Burp Suite的使用介绍

    在网上找了一篇关于Burp Suite的使用介绍,感觉写的基础的,下面就copy了,另外还有一篇<BurpSuite实战指南>的pdf是一位好心的“前辈”共享的https://www.gi ...

  6. 训练指南 UVALive - 3713 (2-SAT)

    layout: post title: 训练指南 UVALive - 3713 (2-SAT) author: "luowentaoaa" catalog: true mathja ...

  7. ASP.NET Core 2.2 基础知识(十) Web服务器 - Kestrel

    ASP.NET Core 应用与进程内的 HTTP 服务器实现一起运行.该服务器实现侦听 HTTP 请求,并在一系列请求功能被写到 HttpContext 时,将这些请求展现到应用中. ASP.NET ...

  8. SQL Loader with utf8

    alter this line in your control file characterset UTF8 to this characterset UTF8 length semantics ch ...

  9. RPD Volume 172 Issue 1-3 December 2016 评论02

    Introduction to the special issue of Radiation Protection Dosimetry This special issue is a collecti ...

  10. JavaScript中的局部作用域及常量的定义

    局部作用域 通常JavaScript的作用域是函数内部,在类似for循环的语句块中是无法申明局部变量的. function exm() { for (var i=0; i<100; i++) { ...