python 以其结构严格著称,同时也以其命名规范散漫出名,算乱无规矩的命名尤其给开发人员带来理解上的误区。
尤其像python、ruby动态语言,由于在运行期随时可能出现方法或者属性的增减,规则的命名尤其重要。
ruby语言本身定义的语法规则较为随意,但却不乏一一对应的隐含规则,使人一目了然。其命名规则甚至渗透进了语言本身的规范当中
在命名规则这一点上python显得没规没距。需要逐步养成一个好的编码命名规范。
本文从各大站点文章中搜集了一些代码风格,命名规范。便于学习参考。
代码风格:
- 使用空格来表示缩进,而不要使用制表符tab,请勿将两者混用
- 函数间换行至少一行
- 类之间换行至少两行
- dict、list、tuple、参数列表时,应该在逗号,前添加一个空格
- dict中key之后的冒号:应在value与冒号:之间添加空格,而不是:与key之前间
- 较长代码(大于79chars)使用反斜杠\换行。换行后新行的起始处应该与前一个分隔符对齐(是参数换行则与左括号(对齐
- import位于module comments 与 docstring 之后,常量声明之前
- 3.0一下版本的代码文件建议以latin字符编码。3.0以上则推荐utf-8
- 代码中有操作符运算,请注意优先级,优先的操作紧缩,或者加括号
- 等号左右两边请勿加空格
- 尽量不要将多行代码放在同一行
- 少使用inline comments(行后注释)
- block comments (用#开头的多行函数注释),保持与目标函数 相同的缩进
- docstring ,开头一行写上返回值,接下来一行写函数功能描述,后可按照格式>>>func(arg1, arg2, arg3) /r 返回值。以便于测试
- 另外,若要使用subversion,cvs等源代码管理工具。可以在函数的docstring 之后,code之前 写上
- __version__ = "Revision:16dd63848921"
命名规则:
- 尽量少用 ‘l‘ (lowercase letter el), ‘O‘ (uppercase letter oh), or ‘I‘ (uppercase letter eye) 单字母作为变量的命名.-------no l,I,O
- 包和模块应该用短且全小写字母(Modules should have short, all-lowercase names.):thismoduleisnew
- class name 则建议用CapWords(首字母大写)的形式命名:NewClassName
- Exception类则用以Error结尾的字符串命名为宜: NewError
- 全局变量尽量只是设计用于模块内使用,并且可以用import *时,包内的__all__机制来除去全局变量
- 函数名(function name) 尽量都用小写且单词间以_(下划线)连接,另外,大小混合的mixedCase植被允许用于传统类中。function_name(arg1...)
- 函数和方法参数(function and method arguments),self作为实例方法的第一个参数,cls作为类方法的第一个参数,倘若参数名与关键字相同,为了避讳,则应该加个下划线
- 方法名&类实例的属性(method name & instance variable)方法名规则与函数名相同,类实例私有属性 和 类实例的私有方法以单个下划线开头_private_fucntion_name(self)
- 常量;全大写,单词间以_下弧线间隔:THIS_IS_CONSTANT_VAR
- 面向对象设计建议:
- 若对类实例中的属性是设置成public的好还是private好,可以考虑先设置成private,其修改成本更低。
- private不能被第三方使用,因为随时有可能被删除、废弃
- public属性不能用下划线开头
- 避免属性使用大运算量操作
- 倘若不想被子类继承的属性,应该用双下划线开头,且最后没有下划线。这样会启动python的命名识别矫正处理算法,保证不被继承
- joined_lower 可以是函数名 方法名 属性名
- ALL_CAPS 是常量
- StudlyCaps是类名
- camelCase 只有在预先订制好的命名规范中使用
- 属性 interface,_internal, __private
- 尽量避免__private形式,下面两个连接解释了为什么python中没有private声明
最后没时间翻译了,有时间再来。
Reference: http://www.python.org/dev/peps/pep-0008/#naming-conventions
Programming Recommendations
- Code should be written in a way that does not disadvantage other implementations of Python (PyPy, Jython, IronPython, Cython, Psyco, and such).
For example, do not rely on CPython‘s efficient implementation of in-place string concatenation for statements in the form a += b or a = a + b. Those statements run more slowly in Jython. In performance sensitive parts of the library, the ‘‘.join() form should be used instead. This will ensure that concatenation occurs in linear time across various implementations.
- Comparisons to singletons like None should always be done with is or is not, never the equality operators.
Also, beware of writing if x when you really mean if x is not None -- e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!
- When implementing ordering operations with rich comparisons, it is best to implement all six operations (__eq__, __ne__, __lt__, __le__, __gt__, __ge__) rather than relying on other code to only exercise a particular comparison.
To minimize the effort involved, the functools.total_ordering() decorator provides a tool to generate missing comparison methods.
PEP 207 indicates that reflexivity rules are assumed by Python. Thus, the interpreter may swap y > x with x < y, y >= x with x <= y, and may swap the arguments of x == y and x != y. The sort() and min() operations are guaranteed to use the < operator and the max() function uses the > operator. However, it is best to implement all six operations so that confusion doesn‘t arise in other contexts.
- Use class-based exceptions.
String exceptions in new code are forbidden, because this language feature is being removed in Python 2.6.
Modules or packages should define their own domain-specific base exception class, which should be subclassed from the built-in Exception class. Always include a class docstring. E.g.:
class MessageError(Exception): """Base class for errors in the email package."""
Class naming conventions apply here, although you should add the suffix "Error" to your exception classes, if the exception is an error. Non-error exceptions need no special suffix.
- When raising an exception, use raise ValueError(‘message‘) instead of the older form raise ValueError, ‘message‘.
The paren-using form is preferred because when the exception arguments are long or include string formatting, you don‘t need to use line continuation characters thanks to the containing parentheses. The older form will be removed in Python 3.
- When catching exceptions, mention specific exceptions whenever possible instead of using a bare except: clause.
For example, use:
try: import platform_specific_module except ImportError: platform_specific_module = None
A bare except: clause will catch SystemExit and KeyboardInterrupt exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. If you want to catch all exceptions that signal program errors, use except Exception: (bare except is equivalent to except BaseException:).
A good rule of thumb is to limit use of bare ‘except‘ clauses to two cases:
- If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.
- If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise. try...finally can be a better way to handle this case.
- Additionally, for all try/except clauses, limit the try clause to the absolute minimum amount of code necessary. Again, this avoids masking bugs.
Yes:
try: value = collection[key] except KeyError: return key_not_found(key) else: return handle_value(value)
No:
try: # Too broad! return handle_value(collection[key]) except KeyError: # Will also catch KeyError raised by handle_value() return key_not_found(key)
- Context managers should be invoked through separate functions or methods whenever they do something other than acquire and release resources. For example:
Yes:
with conn.begin_transaction(): do_stuff_in_transaction(conn)
No:
with conn: do_stuff_in_transaction(conn)
The latter example doesn‘t provide any information to indicate that the __enter__ and __exit__ methods are doing something other than closing the connection after a transaction. Being explicit is important in this case.
- Use string methods instead of the string module.
String methods are always much faster and share the same API with unicode strings. Override this rule if backward compatibility with Pythons older than 2.0 is required.
- Use ‘‘.startswith() and ‘‘.endswith() instead of string slicing to check for prefixes or suffixes.
startswith() and endswith() are cleaner and less error prone. For example:
Yes: if foo.startswith(‘bar‘): No: if foo[:3] == ‘bar‘:
The exception is if your code must work with Python 1.5.2 (but let‘s hope not!).
- Object type comparisons should always use isinstance() instead of comparing types directly.
Yes: if isinstance(obj, int): No: if type(obj) is type(1):
When checking if an object is a string, keep in mind that it might be a unicode string too! In Python 2.3, str and unicode have a common base class, basestring, so you can do:
if isinstance(obj, basestring):
- For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
Yes: if not seq: if seq: No: if len(seq) if not len(seq)
- Don‘t write string literals that rely on significant trailing whitespace. Such trailing whitespace is visually indistinguishable and some editors (or more recently, reindent.py) will trim them.
- Don‘t compare boolean values to True or False using ==.
Yes: if greeting: No: if greeting == True: Worse: if greeting is True:
- The Python standard library will not use function annotations as that would result in a premature commitment to a particular annotation style. Instead, the annotations are left for users to discover and experiment with useful annotation styles.
Early core developer attempts to use function annotations revealed inconsistent, ad-hoc annotation styles. For example:
- [str] was ambiguous as to whether it represented a list of strings or a value that could be either str or None.
- The notation open(file:(str,bytes)) was used for a value that could be either bytes or str rather than a 2-tuple containing a str value followed by abytes value.
- The annotation seek(whence:int) exhibited an mix of over-specification and under-specification: int is too restrictive (anything with __index__ would be allowed) and it is not restrictive enough (only the values 0, 1, and 2 are allowed). Likewise, the annotation write(b: bytes) was also too restrictive (anything supporting the buffer protocol would be allowed).
- Annotations such as read1(n: int=None) were self-contradictory since None is not an int. Annotations such as source_path(self, fullname:str) -> objectwere confusing about what the return type should be.
- In addition to the above, annotations were inconsistent in the use of concrete types versus abstract types: int versus Integral and set/frozenset versus MutableSet/Set.
- Some annotations in the abstract base classes were incorrect specifications. For example, set-to-set operations require other to be another instance of Set rather than just an Iterable.
- A further issue was that annotations become part of the specification but weren‘t being tested.
- In most cases, the docstrings already included the type specifications and did so with greater clarity than the function annotations. In the remaining cases, the docstrings were improved once the annotations were removed.
- The observed function annotations were too ad-hoc and inconsistent to work with a coherent system of automatic type checking or argument validation. Leaving these annotations in the code would have made it more difficult to make changes later so that automated utilities could be supported.