Python基本书写格式规范

Python 代码书写规范

#目录

目录
一、风格规范 5
1.1 分号 5
1.2 行长度 5
1.3 括号 6
1.4 缩进 7
1.5 空行 8
1.6 空格 8
1.7 Shebang 12
1.8 引号 12
1.9 保留字符 13
1.10 标识符 13
1.11 换行 14
1.12 文件编码 15
1.13 注释 15
1.13.1 块注释 15
1.13.2 行注释 16
1.13.3. 文档注释(Docstring) 16
1.13.4 TODO注释 17
1.13.5 建议 18
1.14 字符串 18
1.15.1 合并(拼接)字符串 19
1.15.2 文档字符串 21
1.15 数字 21
1.16 文件和sockets 23
1.17 导入格式 23
1.18 语句 24
1.19 访问控制 25
1.20 Python 中标识符的命名规范、规则以及关键字 25
1.20.1.命名规定 25
1.20.2.标识符的命名规范: 26
1.20.3.标识符的命名规则: 26
1.20.4.Python中的关键字: 26
1.20.5.特定命名方式 27
1.21 Main 28
二、语言规范 28
2.1 模块 28
2.2 函数和方法 29
2.3 类 30
2.4 Lint 31
2.5 包 32
2.6 异常 32
2.6.1 异常捕获 33
2.7 全局变量 34
(1)函数和方法的参数 34
(2)变量 34
(3)常量 34
(4)异常 34
(5)缩写 34
2.8 嵌套/局部/内部类或函数 35
2.9 列表推导 35
2.10 默认迭代器和操作符 36
2.11 生成器 36
2.12 Lambda函数 36
2.13 条件表达式 36
2.14 默认参数值 37
2.15 属性(properties) 37
2.16 True/False的求值 37
2.17 过时的语言特性 38
2.18 词法作用域(Lexical Scoping) 39
2.19 函数与方法装饰器 39
2.20 线程 39
2.21 威力过大的特性 40
一、风格规范
1.1 分号
每一条语句最后加个分号;这是C、Java、php等语言中不可缺少的部分,但是对于Python分号是可加,可不加的
注:建议最好还是不加分号,因为 Python 是换行来区分代码句的,当然有时候也可以加上。
例:

num1 = 1; num2 =2;
print(num1+num2);
3

就是在一行写多条代码句时,加上分号;不要在行尾加分号,
注意:不要用分号将两条命令放在同一行。
1.2 行长度
每行不超过80个字符
例外情况:
1.长的导入模块语句。
2.注释里的URL。
Python会将圆括号,中括号和花括号中的行隐式的连接起来,你可以利用这个特点。如果需要,你可以在表达式外围增加一对额外的圆括号。
例:
Yes: foo_bar(self,width,height,color=‘black’,design=None,x=‘foo’,
emphasis=None,highlight=0)
if (width == 0 and height == 0 and
color == ‘red’ and emphasis == ‘strong’):
如果一个文本字符串在一行放不下,可以使用圆括号来实现隐式行连接:
x = ('This will build a very long long ’
‘long long long long long long string’)
在注释中,如果必要将长的URL放在一行上。
Yes: # See details at
# http://www。example。com/us/developer/documentation/api/content/v2。0/csv_file_name_extension_full_specification。html

No: # See details at
# http://www。example。com/us/developer/documentation/api/content/
# v20/csv_file_name_extension_full_specification.html
通常来说,一条 Python 语句应在一行内写完,但如果语句很长,可以使用反斜杠\来实现多行语句。

需要注意的是,在成对的大括号{ }、中括号[ ]或小括号( )中的多行语句,不需要使用反斜杠\,
1.3 括号
宁缺毋滥的使用括号。
除非是用于实现行连接,否则不要在返回语句或条件语句中使用括号。不过在元组两边使用括号是可以的。

Yes: if foo:
bar()
while x:
x = bar()
if x and y:
bar()
if not x:
bar()
return foo
for (x,y) in dict。items(): …

No: if (x):
bar()
if not(x):
bar()
return (foo)
1.4 缩进
Python 中实现对代码的缩进,可以使用空格或者 Tab 键实现。但无论是手动敲空格,还是使用 Tab 键,通常情况下都是采用 4 个空格长度作为一个缩进量(默认情况下,一个 Tab 键就表示 4 个空格)。
对于行连接的情况,你应该要么垂直对齐换行的元素(见行长度部分的示例),或者使用4空格的悬挂式缩进(这时第一行不应该有参数):
Yes: # Aligned with opening delimiter
foo = long_function_name(var_one,var_two,
var_three,var_four)
# Aligned with opening delimiter in a dictionary
foo = {
long_dictionary_key: value1 +
value2,

}
# 4-space hanging indent; nothing on first line
foo = long_function_name(
var_one,var_two,var_three,
var_four)
# 4-space hanging indent in a dictionary
foo = {
long_dictionary_key:
long_dictionary_value,

}
No: # Stuff on first line forbidden
foo = long_function_name(var_one,var_two,
var_three,var_four)
# 2-space hanging indent forbidden
foo = long_function_name(
var_one,var_two,var_three,
var_four)
​ # No hanging indent in a dictionary
foo = {
long_dictionary_key:
long_dictionary_value,

}
1.5 空行
导入语句和其他代码之间的两行空白行。每个函数之间有两个空行
空一行:用于类成员函数之间,或者用于区分不同逻辑块。空两行:类与类,类与函数,函数与函数之间。

Yes:

spam(ham[1], {eggs: 2}, [])

No:

spam( ham[ 1 ], { eggs: 2 }, [ ] )
顶级定义之间空两行,方法定义之间空一行。顶级定义之间空两行,比如函数或者类定义。方法定义,类定义与第一个方法之间,都应该空一行。函数或方法中,某些地方要是你觉得合适,就空一行。

1.6 空格
(1) 在二元运算符两边各空一格[=,-,+=,==,>,in,is not, and]:

正确的写法

i = i + 1
submitted += 1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)

不推荐的写法

i=i+1
submitted +=1
x = x2 - 1
hypot2 = x
x + y*y
c = (a+b) * (a-b)
(2) 函数的参数列表中,,之后要有空格

正确的写法

def complex(real, imag):
pass

不推荐的写法

def complex(real,imag):
pass
(3) 函数的参数列表中,默认值等号两边不要添加空格

正确的写法

spam(ham[1], {eggs: 2})

不推荐的写法

spam( ham[1], { eggs : 2 } )
(4) 左括号之后,右括号之前不要加多余的空格

正确的写法

spam(ham[1], {eggs: 2})

不推荐的写法

spam( ham[1], { eggs : 2 } )
(5)字典对象的左括号之前不要多余的空格

正确的写法

dict[‘key’] = list[index]

不推荐的写法

dict [‘key’] = list [index]
(6) 不要为对齐赋值语句而使用的额外空格

正确的写法

x = 1
y = 2
long_variable = 3

不推荐的写法

x = 1
y = 2
long_variable = 3
(7) 不要在逗号, 分号, 冒号前面加空格, 但应该在它们后面加(除了在行尾)
Yes: if x == 4:
print x, y
x, y = y, x
No: if x == 4 :
print x , y
x , y = y , x
不要在逗号, 分号, 冒号前面加空格, 但应该在它们后面加(除了在行尾).
#Yes:
if x == 4:
print x, y
x, y = y, x

No:

    if x == 4 :
         print x , y
     x , y = y , x

参数列表, 索引或切片的左括号前不应加空格.
Yes: spam(1)
no: spam (1)
Yes: dict[‘key’] = list[index]
No: dict [‘key’] = list [index]
在二元操作符两边都加上一个空格, 比如赋值(=), 比较(==, <, >, !=, <>, <=, >=, in, not in, is, is not), 布尔(and, or, not). 至于算术操作符两边的空格该如何使用, 需要你自己好好判断. 不过两侧务必要保持一致。

Yes:

x == 1

No:

x<1

当’=’用于指示关键字参数或默认参数值时, 不要在其两侧使用空格.

Yes:

def complex(real, imag=0.0):
return magic(r=real, i=imag)

No:

def complex(real, imag = 0.0):
return magic(r = real, i = imag)
不要用空格来垂直对齐多行间的标记, 因为这会成为维护的负担(适用于:, #, =等):

Yes:

     foo = 1000  # comment
     long_name = 2  # comment that should not be aligned
     dictionary = {
         "foo": 1,
         "long_name": 2,
         }

No:

     foo       = 1000  # comment
     long_name = 2     # comment that should not be aligned
     dictionary = {
         "foo"      : 1,
         "long_name": 2,
         }

1.7 Shebang
大部分.py文件不必以#!作为文件的开始. 根据 PEP-394 , 程序的main文件应该以 #!/usr/bin/Python2或者 #!/usr/bin/Python3开始.(译者注: 在计算机科学中, Shebang (也称为Hashbang)是一个由井号和叹号构成的字符串行(#!), 其出现在文本文件的第一行的前两个字符. 在文件中存在Shebang的情况下, 类Unix操作系统的程序载入器会分析Shebang后的内容, 将这些内容作为解释器指令, 并调用该指令, 并将载有Shebang的文件路径作为该解释器的参数. 例如, 以指令#!/bin/sh开头的文件在执行时会实际调用/bin/sh程序.)
#!先用于帮助内核找到Python解释器, 但是在导入模块时, 将会被忽略. 因此只有被直接执行的文件中才有必要加入#!。

1.8 引号
简单说,自然语言使用双引号、机器标示使用单引号,因此代码里多数应该使用 单引号自然语言 使用双引号 “…”
例如错误信息;很多情况还是 unicode,使用u”你好世界”
机器标识 使用单引号 ‘…’
例如 dict 里的 key
正则表达式 使用原生的双引号 r”…”
文档字符串 (docstring) 使用三个双引号 “”“……”“”
1.9 保留字符
下面的列表显示了在Python中的保留字。这些保留字不能用作常数或变数,或任何其他标识符名称。
所有 Python 的关键字只包含小写字母。
and exec not
assert finally or
break for pass
class from print
continue global raise
def if return
del import try
elif in while
else is with
except lambda yield
1.10 标识符
在 Python 中,所有标识符可以包括英文、数字以及下划线(_),但不能以数字开头。Python 中的标识符是区分大小写的。
以下划线开头的标识符是有特殊意义的。
以单下划线开头 _foo 的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用 from xxx import * 而导入。
以双下划线开头的 __foo 代表类的私有成员,以双下划线开头和结尾的 __foo__代表 Python 里特殊方法专用的标识,如 init() 代表类的构造函数。
1.11 换行
Python支持括号内换行,Python 支持括号内的换行。这时有两种情况。
1)第二行缩进到括号的起始处 foo = long_function_name(var_one, var_two, var_three, var_four)
2) 第二行缩进 4 个空格,适用于起始括号就换行的情形
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
使用反斜杠\换行,二元运算符+ .等应出现在行末;长字符串也可以用此法换行 session.query(MyTable).\
filter_by(id=1).\
one()
print 'Hello, ’
‘%s %s!’ %\
(‘Harry’, ‘Potter’)
禁止复合语句,即一行中包含多个语句:
正确的写法
do_first()
do_second()
do_third()
不推荐的写法
do_first();do_second();do_third();
if/for/while一定要换行:
正确的写法
if foo == ‘blah’: do_blah_thing()
不推荐的写法
if foo == ‘blah’: do_blash_thing()

1.12 文件编码
1.国际惯例,文件编码和Python编码格式全部为utf-8,例如在Python代码的开头,要统 一加上 # – coding: utf-8 --。
2.Python代码中,非ascii字符的字符串,请需添加”u”前缀。
3.若出现 Python编码问题,可按照以下操作尝试解决:
import sys
reload(sys)
sys.setdefaultencoding(‘utf-8’)
4.注意:Python3.X 源码文件默认使用utf-8编码,所以可以正常解析中文,无需指定 UTF-8 编码。
5.注意:如果你使用编辑器,同时需要设置 py 文件存储的格式为 UTF-8,否则会出现类似以下错误信息:
SyntaxError: (unicode error) ‘utf-8’ codec can’t decode byte 0xc4 in position 0:
invalid continuation byte
1.13 注释
确保对模块,函数,方法和行内注释使用正确的风格。
1.13.1 块注释
“#”号后空一格,段落件用空行分开(同样需要“#”号)

块注释 # 块注释 # # 块注释 # 块注释

最需要写注释的是代码中那些技巧性的部分。如果你在下次代码审查的时候必须解释一下,那么你应该现在就给它写注释。对于复杂的操作,应该在其操作开始前写上若干行注释。对于不是一目了然的代码,应在其行尾添加注释。

We use a weighted dictionary search to find out where i is in

the array。 We extrapolate position based on the largest num

in the array and the array size and then do binary search to

get the exact number。


if i & (i-1) == 0: # True if i is 0 or a power of 2。
为了提高可读性,注释应该至少离开代码2个空格。(至少使用两个空格和语句分开,注意不要使用无意义的注释.)

正确的写法

x = x + 1 # 边框加粗一个像素

不推荐的写法(无意义的注释)

x = x + 1 # x加1
另一方面,绝不要描述代码。假设阅读代码的人比你更懂Python,他只是不知道你的代码要做什么。

BAD COMMENT: Now go through the b array and make sure whenever i occurs

the next element is i+1

建议:
在代码的关键部分(或比较复杂的地方), 能写注释的要尽量写注释 比较重要的注释段, 使用多个等号隔开, 可以更加醒目, 突出重要性
app = create_app(name, options)

请勿在此处添加 get post等app路由行为 !!!

if name == ‘main’:
app.run()
1.13.2 行注释
至少使用两个空格和语句分开,注意不要使用无意义的注释#
正确的写法 x = x + 1 # 边框加粗一个像素 # 不推荐的写法(无意义的注释) x = x + 1 # x加1
1.13.3. 文档注释(Docstring)
作为文档的Docstring一般出现在模块头部、函数和类的头部,这样在Python中可以通过对象的doc对象获取文档.
编辑器和IDE也可以根据Docstring给出自动提示.
文档注释以 “”" 开头和结尾, 首行不换行, 如有多行, 末行必需换行, 以下是Google的docstring风格示例:

-- coding: utf-8 --“”“Example docstrings. This module demonstrates documentation as specified by the Google Python Style Guide_. Docstrings may extend over multiple lines. Sections are created with a section header and a colon followed by a block of indented text. Example: Examples can be given using either the Example or Examples sections. Sections support any reStructuredText formatting, including literal blocks:: $ Python example_google.py Section breaks are created by resuming unindented text. Section breaks are also implicitly created anytime a new section starts. “””

不要在文档注释复制函数定义原型, 而是具体描述其具体内容, 解释具体参数和返回值等

不推荐的写法(不要写函数原型等废话) def function(a, b): “”“function(a, b) -> list”“” … … # 正确的写法 def function(a, b): “”“计算并返回a到b范围内数据的平均值”“” … …

对函数参数、返回值等的说明采用numpy标准, 如下所示
def func(arg1, arg2):
“”"在这里写函数的一句话总结(如: 计算平均值).
这里是具体描述.
参数
arg1 : int arg1的具体描述
arg2 : int arg2的具体描述
返回值
int
返回值的具体描述
参看
otherfunc : 其它关联函数等…
示例
示例使用doctest格式, 在>>>后的代码可以被文档测试工具作为测试用例自动运行

a=[1,2,3]
print [x + 3 for x in a]
[4, 5, 6]
“”"
(1)文档注释不限于中英文, 但不要中英文混用
(2)文档注释不是越长越好, 通常一两句话能把情况说清楚即可
(3)模块、公有类、公有方法, 能写文档注释的, 应该尽量写文档注释
1.13.4 TODO注释
为临时代码使用TODO注释,它是一种短期解决方案。
TODO注释应该在所有开头处包含”TODO”字符串,紧跟着是用括号括起来的你的名字,email地址或其它标识符。然后是一个可选的冒号。接着必须有一行注释,解释要做什么。主要目的是为了有一个统一的TODO格式,这样添加注释的人就可以搜索到(并可以按需提供更多细节)。写了TODO注释并不保证写的人会亲自解决问题。当你写了一个TODO,请注上你的名字。

TODO(kl@gmail。com): Use a “*” here for string repetition。

TODO(Zeke) Change this to use relations。

如果你的TODO是”将来做某事”的形式,那么请确保你包含了一个指定的日期或者一个特定的事件。
1.13.5 建议
在代码的关键部分(或比较复杂的地方), 能写注释的要尽量写注释
比较重要的注释段, 使用多个等号隔开, 可以更加醒目, 突出重要性
1.14 字符串
就是一系列字符。在Python中,用引号括起的都是字符串,其中的引号可以是单引号,也可以是双引号。这种灵活性让你能够在字符串中包含引号和撇号:
‘I told my friend, “Python is my favorite language!”’
“The language ‘Python’ is named after Monty Python, not the snake.”
“One of Python’s strengths is its diverse and supportive community.”
使用方法修改字符串的大小写:
name = “ada lovelace”
print(name.title())
#输出:Ada Lovelace

方法title() 出现在这个变量的后面。方法 是Python可对数据执行的操作。
在name.title() 中,name 后面的句点(. )让Python对变量name 执行方法title() 指定的操作。每个方法后面都跟着一对括号,这是因为方法通常需要额外的信息来完成其工作。这种信息是在括号内提供的。函数title() 不需要额外的信息,因此它后面的括号是空的。

name = “Ada Lovelace”
print(name.upper())
print(name.lower())
#输出:ADA LOVELACE

ada lovelace

1.15.1 合并(拼接)字符串
Python使用加号(+ )来合并字符串。在这个示例中,我们使用+ 来合并first_name 、空格和last_name ,以得到完整的姓名,其结果如下:
first_name = “ada”
last_name = “lovelace”
full_name = first_name + " " + last_name
print(full_name)
#输出:ada lovelace
Python字符串中,同样可以用\t 和 \n等制表符。
删除字符串末尾多余的空白:
① >>> favorite_language = 'Python ’
② >>> favorite_language
'Python ’
③ >>> favorite_language.rstrip()
‘Python’
④ >>> favorite_language
'Python ’
存储在变量favorite_language 中的字符串末尾包含多余的空白(见①)。你在终端会话中向Python询问这个变量的值时,可看到末尾的空格(见②)。对变
量favorite_language 调用方法rstrip() 后(见③),这个多余的空格被删除了。然而,这种删除只是暂时的,接下来再次询问favorite_language 的值时,你会发
现这个字符串与输入时一样,依然包含多余的空白(见④)。
要永久删除这个字符串中的空白,必须将删除操作的结果存回到变量中:
favorite_language = 'Python ’
favorite_language = favorite_language.rstrip()
你还可以剔除字符串开头的空白:可使用方法 lstrip()

即使参数都是字符串,使用%操作符或者格式化方法格式化字符串。不过也不能一概而论,你需要在+和%之间好好判定。
Yes: x = a + b
x = ‘%s,%s!’ % (imperative,expletive)
x = ‘{},{}!’。format(imperative,expletive)
x = ‘name: %s; score: %d’ % (name,n)
x = ‘name: {}; score: {}’。format(name,n)
No: x = ‘%s%s’ % (a,b) # use + in this case
x = ‘{}{}’。format(a,b) # use + in this case
x = imperative + ‘,’ + expletive + ‘!’
x = ‘name: ’ + name + ‘; score: ’ + str(n)
避免在循环中用+和+=操作符来累加字符串。由于字符串是不可变的,这样做会创建不必要的临时对象,并且导致二次方而不是线性的运行时间。作为替代方案,你可以将每个子串加入列表,然后在循环结束后用”.join”连接列表。
Yes: items = [’

’]
for last_name,first_name in employee_list:
items。append(‘’ % (last_name,first_name))
items。append(‘
%s,%s
’)
employee_table = ‘’。join(items)
No: employee_table = ‘’
for last_name,first_name in employee_list:
employee_table += ‘’ % (last_name,first_name)
employee_table += ‘
%s,%s

在同一个文件中,保持使用字符串引号的一致性。使用单引号’或者双引号”之一用以引用字符串,并在同一文件中沿用。在字符串内可以使用另外一种引号,以避免在字符串中使用。PyLint已经加入了这一检查。
Yes:
Python(‘Why are you hiding your eyes?’)
Gollum(“I’m scared of lint errors。”)
Narrator(‘“Good!” thought a happy Python reviewer。’)
No:
Python(“Why are you hiding your eyes?”)
Gollum(‘The lint。It burns。It burns us。’)
Gollum(“Always the great lint。Watching。Watching。”)
为多行字符串使用三重双引号”””而非三重单引号’’’。当且仅当项目中使用单引号’来引用字符串时,才可能会使用三重’’’为非文档字符串的多行字符串来标识引用。文档字符串必须使用三重双引号”””。不过要注意,通常用隐式行连接更清晰,因为多行字符串与程序其他部分的缩进方式不一致。
1.15.2 文档字符串
Python有一种独一无二的的注释方式: 使用文档字符串。文档字符串是包、模块、类或函数里的第一个语句。这些字符串可以通过对象的doc成员被自动提取,并且被pydoc所用。我们对文档字符串的惯例是使用三重双引号”””( PEP-257 )。
一个文档字符串应该这样组织: 首先是一行以句号,问号或惊叹号结尾的概述(或者该文档字符串单纯只有一行)。接着是一个空行。接着是文档字符串剩下的部分,它应该与文档字符串的第一行的第一个引号对齐。下面有更多文档字符串的格式化规范。

1.15 数字
①整数
在Python中,可对整数执行加(+ )减(- )乘(* )除(/ )求模(%)运算:

2 + 3
5 >>> 3

2
1 >>> 2
*
3
6 >>> 3
/
2
1.5
Python使用两个乘号表示乘方运算:

3 ** 2
9
3 ** 3
27
10 ** 6
1000000
Python还支持运算次序,因此你可在同一个表达式中使用多种运算。你还可以使用括号来修改运算次序,让Python按你指定的次序执行运算,如下所示:
2 + 3*4
14
(2 + 3) * 4
20
空格不影响Python计算表达式的方式,它们的存在旨在让你阅读代码时,能迅速确定先执行哪些运算。
②浮点数
从很大程度上说,使用浮点数时都无需考虑其行为。你只需输入要使用的数字,Python通常都会按你期望的方式处理它们。但需要注意的是,结果包含的小数位数可能是不确定的:
0.2 + 0.1
0.30000000000000004
3 * 0.1
0.30000000000000004
错误的代码,因为:Python发现你使用了一个值为整数(int )的变量,但它不知道该如何解读这个值。Python知道,这个变量表示的可能是数值23,也可能是字符2和3。像上面这样在字符串中使用整数时,需要显式地指出你希望Python将这个整数用作字符串。
age = 23
message = "Happy " + age + “rd Birthday!”
print(message)
为此,可调用函数str() ,它让Python将非字符串值表示为字符串:

age = 23
message = "Happy " + str(age) + “rd Birthday!”
print(message)
1.16 文件和sockets
在文件和sockets结束时,显式的关闭它。
除文件外,sockets或其他类似文件的对象在没有必要的情况下打开,会有许多副作用,例如:
它们可能会消耗有限的系统资源,如文件描述符。如果这些资源在使用后没有及时归还系统,那么用于处理这些对象的代码会将资源消耗殆尽。
持有文件将会阻止对于文件的其他诸如移动、删除之类的操作。
仅仅是从逻辑上关闭文件和sockets,那么它们仍然可能会被其共享的程序在无意中进行读或者写操作。只有当它们真正被关闭后,对于它们尝试进行读或者写操作将会抛出异常,并使得问题快速显现出来。
而且,幻想当文件对象析构时,文件和sockets会自动关闭,试图将文件对象的生命周期和文件的状态绑定在一起的想法,都是不现实的。因为有如下原因:
没有任何方法可以确保运行环境会真正的执行文件的析构。不同的Python实现采用不同的内存管理技术,比如延时垃圾处理机制。延时垃圾处理机制可能会导致对象生命周期被任意无限制的延长。
对于文件意外的引用,会导致对于文件的持有时间超出预期(比如对于异常的跟踪,包含有全局变量等)。
推荐使用 “with”语句 以管理文件:
with open(“hello。txt”) as hello_file:
for line in hello_file:
print line

1.17 导入格式
每个导入应该独占一行。
Yes: import os
import sys
No: import os,sys
导入总应该放在文件顶部,位于模块注释和文档字符串之后,模块全局变量和常量之前。导入应该按照从最通用到最不通用的顺序分组:
1.标准库导入。
2.第三方库导入。
3.应用程序指定导入。
每种分组中,应该根据每个模块的完整包路径按字典序排序,忽略大小写。
import foo
from foo import bar
from foo。bar import baz
from foo。bar import Quux
from Foob import ar

仅对包和模块使用导入模块间共享代码的重用机制.
结论:
使用 import x 来导入包和模块.
使用 from x import y , 其中x是包前缀, y是不带前缀的模块名.
使用 from x import y as z, 如果两个要导入的模块都叫做y或者y太长了.
例如, 模块 sound.effects.echo 可以用如下方式导入:
from sound.effects import echo…echo.EchoFilter(input, output, delay=0.7, atten=4)
导入时不要使用相对名称. 即使模块在同一个包中, 也要使用完整包名. 这能帮助你避免无意间导入一个包两次.

1.18 语句
通常每个语句应该独占一行。
如果测试结果与测试语句在一行放得下,你也可以将它们放在同一行。如果是if语句,只有在没有else时才能这样做。特别地,绝不要对 try/except 这样做,因为try和except不能放在同一行。
Yes:
if foo: bar(foo)
No:

if foo: bar(foo)
else: baz(foo)

try: bar(foo)
except ValueError: baz(foo)

try:
bar(foo)
except ValueError: baz(foo)
1.19访问控制
在Python中,对于琐碎又不太重要的访问函数,你应该直接使用公有变量来取代它们,这样可以避免额外的函数调用开销。当添加更多功能时,你可以用属性(property)来保持语法的一致性。
另一方面,如果访问更复杂,或者变量的访问开销很显著,那么你应该使用像get_foo() 和 set_foo() 这样的函数调用。如果之前的代码行为允许通过属性(property)访问,那么就不要将新的访问函数与属性绑定。任何试图通过老方法访问变量的代码就没法运行,使用者也就会意识到复杂性发生了变化。
1.20 Python 中标识符的命名规范、规则以及关键字
1.20.1.命名规定
包: 应该是简短的、小写的名字。如果下划线可以改善可读性可以加入。如mypackage。
模块: 与包的规范同。如mymodule。
类: 总是使用首字母大写单词串。如MyClass。内部类可以使用额外的前导下划线。
函数&方法: 函数名应该为小写,可以用下划线风格单词以增加可读性。如:myfunction,my_example_function。
注意:混合大小写仅被允许用于这种风格已经占据优势的时候,以便保持向后兼容。
函数和方法的参数 : 总使用“self”作为实例方法的第一个参数。总使用“cls”作为类方法的第一个参数。
核心风格:避免用下划线作为变量名的开始。
因为下划线对解释器有特殊的意义,而且是内建标识符所使用的符号,我们建议程序员避免用下划线作为变量名的开始。一般来讲,变量名_xxx被看作是“私有的”,在模块或类外不可以使用。当变量是私有的时候,用_xxx 来表示变量是很好的习惯。因为变量名__xxx__对Python 来说:“单下划线” 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量;
“双下划线” 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。
以单下划线开头(_foo)的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用“from xxx import *”而导入;以双下划线开头的(__foo)代表类的私有成员;以双下划线开头和结尾的(foo)代表python里特殊方法专用的标识,如 init()代表类的构造函数。
1.20.2.标识符的命名规范:
1.标识符用字母,数字以及下划线组成
2.标识符不能以数字开头
3.标识符不能使用Python关键字和保留字
4.标识符没有长度的限制 但是应该做到简洁
5.标识符严格区分大小写
1.20.3.标识符的命名规则:

Python中标识符的命名要起到见名知意的效果,要让别的程序员能直接看出来是是什么意思。
标识符常见命名方法被称为驼峰命名法:
①小驼峰式命名法(lower camel case): 第一个单词以小写字母开始;第二个单词的首字母大写,例如:myName、aDog
②大驼峰式命名法(upper camel case): 每一个单字的首字母都采用大写字母,例如: FirstName,LastName
不过在程序员中还有一种命名法比较流行,就是用下划线“_”来连接所有的单词,比如: send_buf

1.20.4.Python中的关键字:
Python中的关键子可以通过Python自带的关键字模块来查看,具体代码如下:
import keyword
print(keyword.kwlist)

‘False’, ‘None’, ‘True’, ‘and’, ‘as’, ‘assert’, ‘break’, ‘class’, ‘continue’, ‘def’, ‘del’, ‘elif’, ‘else’, ‘except’, ‘finally’, ‘for’, ‘from’, ‘global’, ‘if’, ‘import’, ‘in’, ‘is’, ‘lambda’, ‘nonlocal’, ‘not’, ‘or’, ‘pass’, ‘raise’, ‘return’, ‘try’, ‘while’, ‘with’, ‘yield’
在进行标识符命名的时候要注意避免关键字冲突。如果在命名时使用了关键字会报 SyntaxError: invalid syntax 语法错误

Python之父Guido推荐的规范
Type Public Internal
Modules lower_with_under _lower_with_under
Packages lower_with_under
Classes CapWords _CapWords
Exceptions CapWords
Functions lower_with_under() _lower_with_under()
Global/Class Constants CAPS_WITH_UNDER _CAPS_WITH_UNDER
Global/Class Variables lower_with_under _lower_with_under
Instance Variables lower_with_under _lower_with_under (protected) or __lower_with_under (private)
Method Names lower_with_under() _lower_with_under() (protected) or __lower_with_under() (private)
Function/Method Parameters lower_with_under
Local Variables lower_with_under
1.20.5.特定命名方式
主要是指 xxx 形式的系统保留字命名法。项目中也可以使用这种命名,它的意义在于这种形式的变量是只读的,这种形式的类成员函数尽量不要重载。如
class Base(object):
def init(self, id, parent = None):
self.id = id
self.parent = parent
def message(self, msgid):

…略

其中 idparentmessage 都采用了系统保留字命名法。
附:Google Python命名规范
module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_VAR_NAME, instance_var_name, function_parameter_name, local_var_name.
1.21 Main
即使是一个打算被用作脚本的文件,也应该是可导入的。并且简单的导入不应该导致这个脚本的主功能(main functionality)被执行,这是一种副作用。主功能应该放在一个main()函数中。
在Python中,pydoc以及单元测试要求模块必须是可导入的。你的代码应该在执行主程序前总是检查 if name == ‘main’ ,这样当模块被导入时主程序就不会被执行。
def main():
TODO…

if name == ‘main’:
main()
所有的顶级代码在模块导入时都会被执行。要小心不要去调用函数,创建对象,或者执行那些不应该在使用pydoc时执行的操作。

二、语言规范
2.1 模块
每个文件应该包含一个许可样板。根据项目使用的许可(例如,Apache 2.0,BSD,LGPL,GPL),选择合适的样板。
模块尽量使用小写命名,首字母保持小写,尽量不要用下划线(除非多个单词,且数量不多的情况)

正确的模块名

import decoder
import html_parser

不推荐的模块名

import Decoder

2.2 函数和方法
下文所指的函数,包括函数,方法,以及生成器。
一个函数必须要有文档字符串,除非它满足以下条件:
1.外部不可见。
2.非常短小。
3.简单明了。
文档字符串应该包含函数做什么,以及输入和输出的详细描述。通常,不应该描述”怎么做”,除非是一些复杂的算法。文档字符串应该提供足够的信息,当别人编写代码调用该函数时,他不需要看一行代码,只要看文档字符串就可以了。对于复杂的代码,在代码旁边加注释会比使用文档字符串更有意义。
关于函数的几个方面应该在特定的小节中进行描述记录,这几个方面如下文所述。每节应该以一个标题行开始。标题行以冒号结尾。除标题行外,节的其他内容应被缩进2个空格。
Args:
列出每个参数的名字,并在名字后使用一个冒号和一个空格,分隔对该参数的描述。如果描述太长超过了单行80字符,使用2或者4个空格的悬挂缩进(与文件其他部分保持一致)。描述应该包括所需的类型和含义。如果一个函数接受foo(可变长度参数列表)或者bar (任意关键字参数),应该详细列出foo和bar。
Returns: (或者 Yields: 用于生成器)
描述返回值的类型和语义。如果函数返回None,这一部分可以省略。
Raises:
列出与接口有关的所有异常。
def fetch_bigtable_rows(big_table,keys,other_silly_variable=None):
“”“Fetches rows from a Bigtable。

Retrieves rows pertaining to the given keys from the Table instance
represented by big_table。 Silly things may happen if
other_silly_variable is not None。

Args:
big_table: An open Bigtable Table instance。
keys: A sequence of strings representing the key of each table row
to fetch。
other_silly_variable: Another optional variable,that has a much
longer name than the other args,and which does nothing。

Returns:
A dict mapping keys to the corresponding table row data
fetched。Each row is represented as a tuple of strings。For
example:

{‘Serak’: (‘Rigel VII’,‘Preparer’),
‘Zim’: (‘Irk’,‘Invader’),
‘Lrrr’: (‘Omicron Persei 8’,‘Emperor’)}

If a key from the keys argument is missing from the dictionary,
then that row was not found in the table。

Raises:
IOError: An error occurred accessing the bigtable。Table object。
“””
pass
2.3 类
类应该在其定义下有一个用于描述该类的文档字符串。如果你的类有公共属性(Attributes),那么文档中应该有一个属性(Attributes)段。并且应该遵守和函数参数相同的格式。
class SampleClass(object):
“”“Summary of class here。

Longer class information…
Longer class information…

Attributes:
likes_spam: A boolean indicating if we like SPAM or not。
eggs: An integer count of the eggs we have laid。
“””

def init(self,likes_spam=False):
“”“Inits SampleClass with blah。”“”
self.likes_spam = likes_spam
self.eggs = 0

def public_method(self):
“”“Performs operation blah。”“”
如果一个类不继承自其它类,就显式的从object继承。嵌套类也一样。
Yes: class SampleClass(object):
pass

class OuterClass(object):

class InnerClass(object):
pass


class ChildClass(ParentClass):
“”“Explicitly inherits from another class already。”“”
No: class SampleClass:
pass


class OuterClass:

class InnerClass:
pass
继承自 object 是为了使属性(properties)正常工作,并且这样可以保护你的代码,使其不受 PEP-3000 的一个特殊的潜在不兼容性影响。这样做也定义了一些特殊的方法,这些方法实现了对象的默认语义,包括 newinitdelattrgetattributesetattrhashrepr,and str
2.4 Lint
对代码运行pylint
定义:
pylint是一个在Python源代码中查找bug的工具. 对于C和C++这样的不那么动态的(译者注: 原文是less dynamic)语言, 这些bug通常由编译器来捕获. 由于Python的动态特性, 有些警告可能不对. 不过伪告警应该很少。
优点:
可以捕获容易忽视的错误, 例如输入错误, 使用未赋值的变量等.
缺点:
pylint不完美. 要利用其优势, 我们有时侯需要: a) 围绕着它来写代码 b) 抑制其告警 c) 改进它, 或者d) 忽略它.
结论:
确保对你的代码运行pylint.抑制不准确的警告,以便能够将其他警告暴露出来。
可以通过设置一个行注释来抑制警告. 例如:
dict = ‘something awful’ # Bad Idea… pylint: disable=redefined-builtin
pylint警告是以一个数字编号(如 C0112 )和一个符号名(如 empty-docstring )来标识的. 在编写新代码或更新已有代码时对告警进行抑制, 推荐使用符号名来标识.
如果警告的符号名不够见名知意,那么请对其增加一个详细解释。采用这种抑制方式的好处是我们可以轻松查找抑制并回顾它们.
可以使用命令 pylint --list-msgs 来获取pylint告警列表. 你可以使用命令 pylint --help-msg=C6409 , 以获取关于特定消息的更多信息.
相比较于之前使用的 pylint: disable-msg , 本文推荐使用 pylint: disable .
要抑制”参数未使用”告警, 你可以用””作为参数标识符, 或者在参数名前加”unused”. 遇到不能改变参数名的情况, 你可以通过在函数开头”提到”它们来消除告警. 例如:
def foo(a, unused_b, unused_c, d=None, e=None):
_ = d, e
return a

2.5 包
使用模块的全路径名来导入每个模块,避免模块名冲突. 查找包更容易,部署代码变难, 因为你必须复制包层次,所有的新代码都应该用完整包名来导入每个模块.
应该像下面这样导入:

#Reference in code with complete name.import sound.effects.echo

#Reference in code with just module name (preferred).from sound.effects import echo

2.6 异常
允许使用异常, 但必须小心
异常是一种跳出代码块的正常控制流来处理错误或者其它异常条件的方式.
异常必须遵守特定条件:
1,像这样触发异常: raise MyException(“Error message”) 或者 raise MyException . 不要使用两个参数的形式( raise MyException, “Error message” )或者过时的字符串异常( raise “Error message” ).
2,模块或包应该定义自己的特定域的异常基类, 这个基类应该从内建的Exception类继承. 模块的异常基类应该叫做”Error”.
3,永远不要使用 except: 语句来捕获所有异常, 也不要捕获 Exception 或者 StandardError , 除非你打算重新触发该异常, 或者你已经在当前线程的最外层(记得还是要打印一条错误消息). 在异常这方面, Python非常宽容, except: 真的会捕获包括Python语法错误在内的任何错误. 使用 except: 很容易隐藏真正的bug.
4,尽量减少try/except块中的代码量. try块的体积越大, 期望之外的异常就越容易被触发. 这种情况下, try/except块将隐藏真正的错误.
5,使用finally子句来执行那些无论try块中有没有异常都应该被执行的代码. 这对于清理资源常常很有用, 例如关闭文件.
6,当捕获异常时, 使用 as 而不要用逗号. 例如
try:
raise Errorexcept Error as error:
pass

2.6.1 异常捕获

  1. 尽量只包含容易出错的位置,不要把整个函数 try catch。​
  2. 对于不会出现问题的代码,就不要再用 try catch了。​
  3. 只捕获有意义,能显示处理的异常。​
  4. 能通过代码逻辑处理的部分,就不要用 try catch。​
  5. 异常忽略,一般情况下异常需要被捕获并处理,但有些情况下异常可被忽略,只需要用 log 记录即可。
    def ignored():
    try:
    yield
    except Exceptions as e:
    logger.warning(e)
    pass
    2.7 全局变量
    函数&方法
    函数名应该为小写,可以用下划线风格单词以增加可读性。如:myfunction,my_example_function。
    注意:混合大小写仅被允许用于这种风格已经占据优势的时候,以便保持向后兼容。
    对于from M import *导入语句,如果想阻止导入模块内的全局变量可以使用旧有的规范,在全局变量上加一个前导的下划线。
    注意:应避免使用全局变量

(1)函数和方法的参数
总使用“self”作为实例方法的第一个参数。总使用“cls”作为类方法的第一个参数。
如果一个函数的参数名称和保留的关键字冲突,通常使用一个后缀下划线好于使用缩写或奇怪的拼写。

(2)变量
变量名全部小写,由下划线连接各个单词。如color = WHITE,this_is_a_variable = 1
注意:
1.不论是类成员变量还是全局变量,均不使用 m 或 g 前缀。
2.私有类成员使用单一下划线前缀标识,多定义公开成员,少定义私有成员。
3.变量名不应带有类型信息,因为Python是动态类型语言。如 iValue、names_list、dict_obj 等都是不好的命名。
(3)常量
常量名所有字母大写,由下划线连接各个单词如MAX_OVERFLOW,TOTAL。
(4)异常
以“Error”作为后缀。
(5)缩写
命名应当尽量使用全拼写的单词,缩写的情况有如下两种:
1.常用的缩写,如XML、ID等,在命名时也应只大写首字母,如XmlParser。
2.命名中含有长单词,对某个单词进行缩写。这时应使用约定成俗的缩写方式。
避免使用全局变量,用类变量来代替。但也有一些例外:
1.脚本的默认选项。
2.模块级常量。例如:PI = 3.14159。常量应该全大写,用下划线连接。
3.有时候用全局变量来缓存值或者作为函数返回值很有用。
4.如果需要,全局变量应该仅在模块内部可用,并通过模块级的公共函数来访问。
2.8 嵌套/局部/内部类或函数
类可以定义在方法,函数或者类中。函数可以定义在方法或函数中。封闭区间中定义的变量对嵌套函数是只读的。
2.9 列表推导
适用于简单情况。每个部分应该单独置于一行:映射表达式,for语句,过滤器表达式。禁止多重for语句或过滤器表达式。复杂情况下还是使用循环。
Yes:
result = []
for x in range(10):
for y in range(5):
if x * y > 10:
result。append((x,y))

for x in xrange(5):
for y in xrange(5):
if x != y:
for z in xrange(5):
if y != z:
yield (x,y,z)

return ((x,complicated_transform(x))
for x in long_generator_function(parameter)
if x is not None)

squares = [x * x for x in range(10)]

eat(jelly_bean for jelly_bean in jelly_beans
if jelly_bean。color == ‘black’)
No:
result = [(x,y) for x in range(10) for y in range(5) if x * y > 10]

return ((x,y,z)
for x in xrange(5)
for y in xrange(5)
if x != y
for z in xrange(5)
if y != z)
2.10 默认迭代器和操作符
容器类型,像字典和列表,定义了默认的迭代器和关系测试操作符(in和not in)。
默认操作符和迭代器简单高效,它们直接表达了操作,没有额外的方法调用。使用默认操作符的函数是通用的。它可以用于支持该操作的任何类型。
如果类型支持,就使用默认迭代器和操作符,例如列表,字典和文件。内建类型也定义了迭代器方法。优先考虑这些方法,而不是那些返回列表的方法。这样遍历容器时,你将不能修改容器。
Yes: for key in adict:
if key not in adict:
if obj in alist:
for line in afile:
for k,v in dict。iteritems():
No: for key in adict。keys():
if not adict。has_key(key):
for line in afile。readlines():
2.11 生成器
所谓生成器函数,就是每当它执行一次生成(yield)语句,它就返回一个迭代器,这个迭代器生成一个值。生成值后,生成器函数的运行状态将被挂起,直到下一次生成。
简化代码,因为每次调用时,局部变量和控制流的状态都会被保存。比起一次创建一系列值的函数,生成器使用的内存更少。
注意在生成器函数的文档字符串中使用”Yields”而不是”Returns”。
2.12 Lambda函数
适用于单行函数。如果代码超过60-80个字符,最好还是定义成常规(嵌套)函数。
对于常见的操作符,例如乘法操作符,使用operator 模块中的函数以代替lambda函数。
2.13 条件表达式
条件表达式是对于if语句的一种更为简短的句法规则。比if语句更加简短和方便,但比if语句难于阅读。如果表达式很长,难于定位条件。
适用于单行函数。在其他情况下,推荐使用完整的if语句。
2.14 默认参数值
在函数参数列表的最后指定变量的值,例如:def foo(a,b = 0): 。如果调用foo时只带一个参数,则b被设为0。如果带两个参数,则b的值等于第二个参数。
经常会碰到一些使用大量默认值的函数,但偶尔想要覆盖这些默认值。默认参数值提供了一种简单的方法来完成这件事,你不需要为这些罕见的例外定义大量函数。同时,Python也不支持重载方法和函数,默认参数是一种”仿造”重载行为的简单方式。
默认参数只在模块加载时求值一次。如果参数是列表或字典之类的可变类型,这可能会导致问题。如果函数修改了对象(例如向列表追加项),默认值就被修改了。
不要在函数或方法定义中使用可变对象作为默认值。
Yes: def foo(a,b=None):
if b is None:
b = []
No: def foo(a,b=[]):
No: def foo(a,b=time。time()): # The time the module was loaded???

No:  def foo(a,b=FLAGS。my_thing):  # sys。argv has not yet been parsed

2.15 属性(properties)
一种用于包装方法调用的方式。当运算量不大,它是获取和设置属性(attribute)的标准方式。
通过消除简单的属性(attribute)访问时显式的get和set方法调用,可读性提高了。允许懒惰的计算。用Pythonic的方式来维护类的接口。就性能而言,当直接访问变量是合理的,添加访问方法就显得琐碎而无意义。使用属性(properties)可以绕过这个问题。将来也可以在不破坏接口的情况下将访问方法加上。
属性(properties)是在get和set方法声明后指定,这需要使用者在接下来的代码中注意: set和get是用于属性(properties)的(除了用 @property 装饰器创建的只读属性)。必须继承自object类。可能隐藏比如操作符重载之类的副作用。继承时可能会让人困惑。
通常习惯于使用访问或设置方法来访问或设置数据,它们简单而轻量。不过我们建议你在新的代码中使用属性。只读属性应该用 @property装饰器来创建。
如果子类没有覆盖属性,那么属性的继承可能看上去不明显。因此使用者必须确保访问方法间接被调用,以保证子类中的重载方法被属性调用(使用模板方法设计模式)。
2.16 True/False的求值
尽可能使用隐式false。
Python在布尔上下文中会将某些值求值为false。按简单的直觉来讲,就是所有的”空”值都被认为是false。因此0、None、[]、{}、“” 都被认为是false。
使用Python布尔值的条件语句更易读也更不易犯错,也更快。
尽可能使用隐式的false,例如: 使用if foo: 而不是 if foo != []: 。
注意事项:
不要用或者!=来比较单件,比如None。使用is或者is not。
当你写下if x:时,你其实表示的是if x is not None。例如: 当你要测试一个默认值是None的变量或参数是否被设为其它值。这个值在布尔语义下可能是false!
永远不要用
将一个布尔量与false相比较。使用 if not x:代替。如果你需要区分false和None,你应该用像 if not x and x is not None: 这样的语句。
对于序列(字符串,列表,元组),要注意空序列是false。因此 if not seq: 或者 if seq: 比 if len(seq): 或 if not len(seq): 要更好。
处理整数时,使用隐式false可能会得不偿失(即不小心将None当做0来处理)。你可以将一个已知是整型(且不是len()的返回结果)的值与0比较。
Yes: if not users:
print ‘no users’

if foo == 0:
self。handle_zero()

if i % 10 == 0:
self。handle_multiple_of_ten()

No: if len(users) == 0:
print ‘no users’

if foo is not None and not foo:
self。handle_zero()

if not i % 10:
self。handle_multiple_of_ten()
2.17 过时的语言特性
尽可能使用字符串方法取代字符串模块. 使用函数调用语法取代apply(). 使用列表推导, for循环取代filter(), map()以及reduce().
我们不使用不支持这些特性的Python版本, 所以没理由不用新的方式.
Yes: words = foo.split(‘:’)
[x[1] for x in my_list if x[2] == 5]
map(math.sqrt, data) # Ok. No inlined lambda expression.
fn(*args, **kwargs)
No: words = string.split(foo, ‘:’)
map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))
apply(fn, args, kwargs)
2.18 词法作用域(Lexical Scoping)
嵌套的Python函数可以引用外层函数中定义的变量, 但是不能够对它们赋值. 变量绑定的解析是使用词法作用域, 也就是基于静态的程序文本. 对一个块中的某个名称的任何赋值都会导致Python将对该名称的全部引用当做局部变量, 甚至是赋值前的处理. 如果碰到global声明, 该名称就会被视作全局变量。

2.19 函数与方法装饰器
用于函数及方法的装饰器 (也就是@标记)。最常见的装饰器是@classmethod和@staticmethod,用于将常规函数转换成类方法或静态方法。不过,装饰器语法也允许用户自定义装饰器。特别地,对于某个函数my_decorator,下面的两段代码是等效的:
class C(object):
@my_decorator
def method(self):
# method body 。。。
class C(object):
def method(self):
# method body 。。。
method = my_decorator(method)
优雅的在函数上指定一些转换。该转换可能减少一些重复代码,保持已有函数不变(enforce invariants)等。
装饰器可以在函数的参数或返回值上执行任何操作,这可能导致让人惊异的隐藏行为。而且,装饰器在导入时执行。从装饰器代码的失败中恢复更加不可能。
如果好处很显然,就明智而谨慎的使用装饰器。装饰器应该遵守和函数一样的导入和命名规则。装饰器的Python文档应该清晰的说明该函数是一个装饰器。请为装饰器编写单元测试。
避免装饰器自身对外界的依赖(即不要依赖于文件,socket,数据库连接等),因为装饰器运行时这些资源可能不可用(由 pydoc 或其它工具导入)。应该保证一个用有效参数调用的装饰器在所有情况下都是成功的。
2.20 线程
优先使用Queue模块的 Queue 数据类型作为线程间的数据通信方式. 另外, 使用threading模块及其锁原语(locking primitives). 了解条件变量的合适使用方式, 这样你就可以使用 threading.Condition 来取代低级别的锁了。
2.21 威力过大的特性
避免使用这些特性
Python是一种异常灵活的语言, 它为你提供了很多花哨的特性, 诸如元类(metaclasses), 字节码访问, 任意编译(on-the-fly compilation), 动态继承, 对象父类重定义(object reparenting), 导入黑客(import hacks), 反射, 系统内修改(modification of system internals), 等等。
在代码中避免这些特性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值