Size: 17589
Comment:
|
Size: 19769
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 3: | Line 3: |
【Twisted开发方式】 本文写给那些想要为Twisted编写代码的人。 o 编码标准 o 文档标准 o 测试标准 o 从Twisted的一个子版本开始干 【Twisted编码标准】 1. 命名 2. 测试 3. 空白缩进 4. 模块 5. 包 6. doc文档 7. 脚本 8. 标准库扩展模块 9. 变更日志 10. class 11. method 12. 回调参数 13. 特殊方法 14. function 15. 属性 16. 数据库 17. c代码 18. checkin信息 19. 建议 【命名】 应该选择一个容易记又有具体含义的名字。模块的命名可以随意一些(例如 twisted.spread ...),但是类命名必须十分清晰明了。写代码的时候请保证手边就有字典或是辞典,方便随时查看。 应该避免用一个术语表示多种含义。要避免这个问题比想象中难的多,因为大多数常用的单词已经被许多其它软件用过了,所以这个规则经常被破坏。更重要的是,应该避免使用那些没有任何意义的单词。特别是像handler、processor、engine、manager和component这些词,这些词只能说明某个东西确实能做一些事情,但是并不能真的表述出这个东西的实际功能, 在命名和python的doc字串请使用美式拼写方法。例如,对于像filesystem这样的合成技术名词,在编码和doc字串中都应该使用没有连字符的拼写方式,以避免不必要的单词首字母大写问题。 |
''' Twisted编码标准 (Twisted Coding Standard) ''' [[TableOfContents]] = 命名(Naming) = 应该选择一个容易记又有具体含义的名字。模块的命名可以随意一些(例如 twisted.spread ...),但是类命名必须十分清晰明了。写代码的时候请保证手边就有字典或是辞典,方便随时查看。 Try to choose names which are both easy to remember and meaningful. Some silliness is OK at the module naming level (see twisted.spread...) but when choosing class names, be as precise as possible. Write code with a dictionary and thesaurus open on the table next to you. 应该避免用一个术语表示多种含义。要避免这个问题比想象中难的多,因为大多数常用的单词已经被许多其它软件用过了,所以这个规则经常被破坏。更重要的是,应该避免使用那些没有任何意义的单词。特别是像handler、processor、engine、manager和component这些词,这些词只能说明某个东西确实能做一些事情,但是并不能真的表述出这个东西的实际功能, Try to avoid overloaded terms. This rule is often broken, since it is incredibly difficult, as most normal words have already been taken by some other software. More importantly, try to avoid meaningless words. In particular, words like handler, processor, engine, manager and component don't really indicate what something does, only that it does something. 在命名和python的doc字串请使用美式拼写方法。例如,对于像filesystem这样的合成技术名词,在编码和doc字串中都应该使用没有连字符的拼写方式,以避免不必要的单词首字母大写问题。 Use American spelling in both names and docstrings. For compound technical terms such as 'filesystem', use a non-hyphenated spelling in both docstrings and code in order to avoid unnecessary capitalization. = 测试(Testing) = 单元测试应该使用twisted.trial框架编写。twisted.test包中有许多例子可以参考。测试模块的名称应该以“test_”开头。每个源码文件中都应该有一个“test-case-name”标签来指定与之相关的测试代码。 Unit tests are written using the twisted.trial framework. Many examples are in the twisted.test package. Test modules should start with 'test_' in their name. Source files should have test-case-name tags that point to their related tests. 验收测试(acceptance test)现在全部由admin/accepttests中的脚本自动完成。(TODO: 真正的验收测试策略) Acceptance tests are all automated by the admin/accepttests script currently. (TODO: real acceptance tests strategy!) 在你checkin任何修改之前,请运行单元测试来测试你的代码。 Run the unit tests tests before you check anything in. 再次重申,在你checkin任何修改之前,请运行单元测试来测试你代码。由于验收测试通常是不可移植的,并且在某些情况下验收测试自身的运行也会出错,所以出现破坏功能约束的代码这种事儿也是不可避免的,我们也能理解,也可以原谅的。但如果不进行验收测试就提交代码,并造成了对原有功能的损害,就可能会导致从“大家对你的代码所造成的破坏的无情嘲弄”到“取消你在cvs上的commit权限”等各种后果。 Let me repeat that, for emphasis: run the unit tests before you check anything in. Code which breaks functionality is unfortunate and unavoidable. The acceptance tests are highly nonportable and sometimes a pain to run, so this is pardonable. Code which breaks the unit tests in a way that you could have prevented by running them yourself, however, may be grounds for anything from merciless taunting through revertion of the breakage to revocation of cvs commit privileges. 强烈建议开发者学会使用Emacs,并在Emacs中把TwistedEmacs包中的twisted-dev.el文件与F9绑定在一起用来运行单元测试。其它编辑器中现在还没有做类似的支持,但是如果您确实有需要,我们很乐意提供给你。 It is strongly suggested that developers learn to use Emacs, and use the twisted-dev.el file included in the TwistedEmacs package to bind the F9 key to run unit tests and bang on it frequently. Support for other editors is unavailable at this time but we would love to provide it. 如果你修改或是撰写了一个新的HOWTO文档,请参考Lore documentation来学习文档的编写格式。 If you modify, or write a new, HOWTO, please read the Lore documentation to learn the format the docs. = 空白缩进(Whitespace) = 每个缩进的大小为4个空格键,不允许使用Tab键。强烈建议为每个代码段另起一行,这使代码中的控制结构的缩进更清晰。 Indentation is 4 spaces per indent. Tabs are not allowed. It is preferred that every block appear on a new line, so that control structure indentation is always visible. = 模块(Modules) = 模块的名称全部小写,并尽可短,最好是一个单词。如果模块的名称包含多个单词,可以使用下划线分隔或是直接将几个单词连起来写。 Modules must be named in all lower-case, preferably short, single words. If a module name contains multiple words, they may be separated by underscores or not separated at all. 大多数情况下,模块应该包含多个类,函数或是方法。如果一个模块只包含一个对象,可以考虑通过代码重构将一些相关的功能包含的该模块中。 In most cases, modules should contain more than one class, function, or method; if a module contains only one object, consider refactoring to include more related functionality in that module. 根据具体情况,下面的几种import方式都是可以的: Depending on the situation, it is acceptable to have imports that look like this: {{{ from twisted.internet.defer import Deferred }}} 或是: or like this: {{{ from twisted.internet import defer }}} 也就是说,可以通过from ... import语句来导入module、class和function,但是不能通过from ... import语句导入一个package。 That is, modules should import modules or classes and functions, but not packages. = 包(Packages) = 包的命名规则与模块大体相同。所有的模块都要封装在某包中。嵌套的包可以用来进一步组织相关的模块。 Package names should follow the same conventions as module names. All modules must be encapsulated in some package. Nested packages may be used to further organize related modules. __init__.py文件中除了doc信息和一个可选的__all__属性之外,不能包含任何其它的东西。包和模块是不同的东西,应该区别对待。但是在代码重构中,如果一个模块被用来构造一个嵌套包中的一部分时,为了保证向后兼容,则不得不破坏这个规则。 __init__.py must never contain anything other than a docstring and (optionally) an __all__ attribute. Packages are not modules and should be treated differently. This rule may be broken to preserve backwards compatibility if a module is made into a nested package as part of a refactoring. 如果你想把一个模块升级为一个包(例如:为了将一个很大的模块分隔为多个较小的文件),使用“导入模块”进行升级是一个较好的方法,下面是一个例子: If you wish to promote code from a module to a package, for example, to break a large module out into several smaller files, the accepted way to do this is to promote from within the module. For example, {{{ # parent/ # --- __init__.py --- import child }}} {{{ # --- child.py --- import parent class Foo: pass parent.Foo = Foo }}} 每个包都应该放到setup.py的列表中。 Every package should be added to the list in setup.py. 多个包之间不可以有循环依赖。为了简化维护工作,两个不同的包之间不应该同时进行相互导入。在Twisted中,所有的包都遵循上述约定。应该特别注意一个名为twisted.python的包,要保证这个包不能与Twisted中任何一个其它的包产生依赖关系。 Packages must not depend circularly upon each other. To simplify maintaining this state, packages must also not import each other circularly. While this applies to all packages within Twisted, one twisted.python deserves particular attention, as it may not depend on any other Twisted package. = doc文档(Docstrings) = 只要条件允许,就应该使用doc文档来描述python中的方法、函数、类和模块的功能信息。如果某些时候需要完全避免文档描述信息(例如,一个还在开发阶段的接口),可以插入一个doc文档的占位符(例如:“UNDOCUMENT”就不错,^_^)。这样就不会错误地将其它无用注释作为该方法、函数、类或是模块的doc文档信息,包含到那些自动产生的API文档中。 Wherever possible, docstrings should be used to describe the purpose of methods, functions, classes, and modules. In cases where it's desirable to avoid documenting thoroughly -- for example, and evolving interface -- insert a placeholder docstring ("UNDOCUMENTED" is preferred), so that the auto-generated API documentation will not pick up an extraneous comment as the documentation for that module/class/function. doc文档从不用来提供一个对象语义信息。如果这些代码将用于一个确实有这样需求的系统中(例如:Zope),可能会违反这个规则。 Docstrings are never to be used to provide semantic information about an object; this rule may be violated if the code in question is to be used in a system where this is a requirement (such as Zope). doc文档应该与它所描述的代码具有相同的缩进级别。 Docstrings should be indented to the level of the code they are documenting. doc文档应该用三个双引号开头。 Docstrings should be triple-quoted. doc文档用epytext格式书写,更多的信息请参考Epytext Markup Language document。 Docstrings should be written in epytext format; more documentation is available in the Epytext Markup Language documentation. 此外,建议Emacs的用户: Additionally, to accommodate emacs users: * doc文档中的单引号应该使用其转义形式书写,以防止Emacs将文件中的其它部分误认为是一个String * Single quotes of the type of the docstring's triple-quote should be escaped. This will prevent font-lock from accidentally fontifying large portions of the file as a string. * doc文档中的代码示例应该用|开头,以防止IM-Python将doc文档中的示例代码当作真正的代码 * Code examples in docstrings should be prefixed by the | character. This will prevent IM-Python from regarding sample code as real functions, methods, and classes. 例如: For example, {{{ def foo2bar(f): """I am a function to convert foos to bars. I should be used when you have a foo but you want a bar; note that this is a non-destructive operation. If I can\'t convert the foo to a bar I will raise a FooException(). For example:: | import wombat | def sample(something): | f = something.getFoo() | f.doFooThing() | b = wombat.foo2bar(f) | b.doBarThing() | return b """ # Optionally, actual code can go here. }}} {{{ def foo2bar(f): """这个函数用来将foo转换为bar。 当你有一个foo,但是你想要一个bar的时候,可以使用这个函数; 注意这是一个没有破坏性的操作。如果无法(can\'t)将foo转换为bar, 就会产生一个FooException异常。 例如: | import wombat | def sample(something): | f = something.getFoo() | f.doFooThing() | b = wombat.foo2bar() | b.doBarThing() | return b """ # 实际的代码从这里开始 }}} = 脚本(Scripts) = 对于你想让一个Twisted用户通过命令行来执行的每个脚本,都必须做下面的事儿: For each script, that is, a program you expect a Twisted user to run from the command-line, the following things must be done: 在twisted.scripts中编写一个模块,其中包含一个名为run的可调用的全局函数。这个函数会通过不带参数的命令行方式被调用(通常使用sys.argv读取)。如果你认为对其他人有用处,可以在自己的模块中随意添加函数和类供别人使用。 Write a module in twisted.scripts which contains a callable global named run. This will be called by the command line part with no arguments (it will usually read sys.argv). Feel free to write more functions or classes in this module, if you feel they are useful to others. 在bin/目录下编写一个文件,其中包含Twisted的running-from-CVS的头部,并以下面的语句结尾。 Write a file in bin/ which contains the Twisted running-from-CVS header, and ending with {{{ from twisted.scripts.yourmodule import run run() }}} 在doc/man中编写对应的manpage。在debian系统中,你可以找到一个manpage的结构示例,它保存在/usr/share/doc/man-db/examples/manpage.example中。 Write a manpage in doc/man. On debian systems you can find a skeleton example of a manpage in /usr/share/doc/man-db/examples/manpage.example. 把你的脚本添加到setup.py中的脚本列表中。 Add your script to the script list in setup.py. 上面的步骤将确保你的程序能够正确的工作在CVS、Windows和Debian等环境中。 This will insure your program will work correctly for users of CVS, Windows releases and Debian packages. |
Line 38: | Line 237: |
【测试】 单元测试应该使用twisted.trial框架编写。twisted.test包中有许多例子可以参考。测试模块的名称应该以“test_”开头。每个源码文件中都应该有一个“test-case-name”标签来指定与之相关的测试代码。验收测试(acceptance test)现在全部由admin/accepttests中的脚本自动完成。(TODO: 真正的验收测试策略) 在你checkin任何修改之前,请运行单元测试来测试你的代码。 再次重申,在你checkin任何修改之前,请运行单元测试来测试你代码。由于验收测试通常是不可移植的,并且在某些情况下验收测试自身的运行也会出错,所以出现破坏功能约束的代码这种事儿也是不可避免的,我们也能理解,也可以原谅的。但如果不进行验收测试就提交代码,并造成了对原有功能的损害,就可能会导致从“大家对你的代码所造成的破坏的无情嘲弄”到“取消你在cvs上的commit权限”等各种后果。 强烈建议开发者学会使用Emacs,并在Emacs中把TwistedEmacs包中的twisted-dev.el文件与F9绑定在一起用来运行单元测试。其它编辑器中现在还没有做类似的支持,但是如果您确实有需要,我们很乐意提供给你。 如果你修改或是撰写了一个新的HOWTO文档,请参考Lore documentation来学习文档的编写格式。 |
= 标准库扩展模块(Standard Library Extension Modules) = 当使用一个Python中已有模块的新的扩展版本时,请将import语句放到try/except块中,当import扩展模块失败时,可以import原有Python中的对应模块。这样你的代码就能在没有扩展库支持的平台上维持运行了。例如: When using the extension version of a module for which there is also a Python version, place the import statement inside a try/except block, and import the Python version if the import fails. This allows code to work on platforms where the extension version is not available. For example: {{{ try: import cPickle as pickle except ImportError: import pickle }}} 使用import语句中的as语法,将扩展模块的名字重新设成与Python中原有模块同名,以覆盖原有的模块。 Use the "as" syntax of the import statement as well, to set the name of the extension module to the name of the Python module. = 变更日志(ChangeLog) = 所有能够影响最终用户使用Twisted方式的变更都要以一个恰当的方式记录在变更日志中,并记录所有的影响。 All changes that will affect the way end-users see Twisted should come with an appropriate entry in the ChangeLog that summarizes that impact. 变更日志的正确格式是GNU的changelog格式。Emacs有个专门的模式用来编辑GNU changelog格式的文件,可以使用M-x来增加一个变更日志项。无论处于何种荒谬可笑的理由,如果你正在使用一个Emacs以外的编辑器编辑Twisted代码,你可以使用Moshe Zadka提供的admin/change脚本来添加一个符合格式要求的日志项。 The correct format for the ChangeLog is GNU changelog format. There is an emacs mode for editing this, use M-x add-change-log-entry. If you are, for whatever absurd reason, using an editor other than emacs to edit Twisted, you can use Moshe Zadka's helpfully provided admin/change script to add a properly-formatted entry. |
Line 45: | Line 267: |
【空白缩进】 每个缩进的大小为4个空格键,不允许使用Tab键。强烈建议为每个代码段另起一行,这使代码中的控制结构的缩进更清晰。 |
|
Line 48: | Line 268: |
【模块】 模块的名称全部小写,并尽可短,最好是一个单词。如果模块的名称包含多个单词,可以使用下划线分隔或是直接将几个单词连起来写。 大多数情况下,模块应该包含多个类,函数或是方法。如果一个模块只包含一个对象,可以考虑通过代码重构将一些相关的功能包含的该模块中。 根据具体情况,下面的几种import方式都是可以的: ------------------------------------------------------ | from twisted.internet.defer import Deferred | ------------------------------------------------------ 或是: --------------------------------------------- | from twisted.internet import defer | --------------------------------------------- 也就是说,可以通过from ... import语句来导入module、class和function,但是不能通过from ... import语句导入一个package。 【包】 包的命名规则与模块大体相同。所有的模块都要封装在某包中。嵌套的包可以用来进一步组织相关的模块。 __init__.py文件中除了doc信息和一个可选的__all__属性之外,不能包含任何其它的东西。包和模块是不同的东西,应该区别对待。但是在代码重构中,如果一个模块被用来构造一个嵌套包中的一部分时,为了保证向后兼容,则不得不破坏这个规则。 如果你想把一个模块升级为一个包(例如:为了将一个很大的模块分隔为多个较小的文件),使用“导入模块”进行升级是一个较好的方法,下面是一个例子: ----------------------------- | # parent/ | | # --- __init__.py --- | | import child | ----------------------------- ----------------------------- | # --- child.py --- | | import parent | | class Foo: | | pass | | | | parent.Foo = Foo | ----------------------------- 每个包都应该放到setup.py的列表中。 多个包之间不可以有循环依赖。为了简化维护工作,两个不同的包之间不应该同时进行相互导入。在Twisted中,所有的包都遵循上述约定。应该特别注意一个名为twisted.python的包,要保证这个包不能与Twisted中任何一个其它的包产生依赖关系。 【doc文档】 只要条件允许,就应该使用doc文档来描述python中的方法、函数、类和模块的功能信息。如果某些时候需要完全避免文档描述信息(例如,一个还在开发阶段的接口),可以插入一个doc文档的占位符(例如:“UNDOCUMENT”就不错,^_^)。这样就不会错误地将其它无用注释作为该方法、函数、类或是模块的doc文档信息,包含到那些自动产生的API文档中。 doc文档从不用来提供一个对象语义信息。如果这些代码将用于一个确实有这样需求的系统中(例如:Zope),可能会违反这个规则。 doc文档应该与它所描述的代码具有相同的缩进级别。 doc文档应该用三个双引号开头。 doc文档用epytext格式书写,更多的信息请参考Epytext Markup Language document。 此外,建议Emacs的用户: o doc文档中的单引号应该使用其转义形式书写,以防止Emacs将文件中的其它部分误认为是一个String o doc文档中的代码示例应该用|开头,以防止IM-Python将doc文档中的示例代码当作真正的代码 例如: ------------------------------------------------------------------------ | def foo2bar(f): | | """这个函数用来将foo转换为bar。 | | 当你有一个foo,但是你想要一个bar的时候,可以使用这个函数; | | 注意这是一个没有破坏性的操作。如果无法(can\'t)将foo转换为bar, | | 就会产生一个FooException异常。 | | 例如: | | | import wombat | | | def sample(something): | | | f = something.getFoo() | | | f.doFooThing() | | | b = wombat.foo2bar() | | | b.doBarThing() | | | return b | | | | """ | | # 实际的代码从这里开始 | | | | | ------------------------------------------------------------------------ 【脚本】 对于你想让一个Twisted用户通过命令行来执行的每个脚本,都必须做下面的事儿: 1. 在twisted.scripts中编写一个模块,其中包含一个名为run的可调用的全局函数。这个函数会通过不带参数的命令行方式被调用(通常使用sys.argv读取)。如果你认为对其他人有用处,可以在自己的模块中随意添加函数和类供别人使用。 2. 在bin/目录下编写一个文件,其中包含Twisted的running-from-CVS的头部,并以 from twisted.scripts.yourmodule import run run() 3. 在doc/man中编写对应的manpage。在debian系统中,你可以找到一个manpage的结构示例,它保存在/usr/share/doc/man-db/examples/manpage.example中。 4. 把你的脚本添加到setup.py中的脚本列表中。 上面的步骤将确保你的程序能够正确的工作在CVS、Windows和Debian等环境中。 【标准库扩展模块】 当使用一个Python中已有模块的新的扩展版本时,请将import语句放到try/except块中,当import扩展模块失败时,可以import原有Python中的对应模块。这样你的代码就能在没有扩展库支持的平台上维持运行了。例如: ------------------------------------- | try: | | import cPickle as pickle | | except ImportError: | | import pickle | ------------------------------------- 使用import语句中的as语法,将扩展模块的名字重新设成与Python中原有模块同名,以覆盖原有的模块。 【变更日志】 所有能够影响最终用户使用Twisted方式的变更都要以一个恰当的方式记录在变更日志中,并记录所有的影响。 变更日志的正确格式是GNU的changelog格式。Emacs有个专门的模式用来编辑GNU changelog格式的文件,可以使用M-x来增加一个变更日志项。无论处于何种荒谬可笑的理由,如果你正在使用一个Emacs以外的编辑器编辑Twisted代码,你可以使用Moshe Zadka提供的admin/change脚本来添加一个符合格式要求的日志项。 【类】 类的命名使用一种混和的拼写方式,类名的首字母要大写,类名中的每个单词的首字母也要大写,用以区分多个单词。如果类名是一些单词的首字母缩写,则所有字母都要大写。类名不需要使用其所在模块的名称作为类名前缀。下面给出了几个符合上述规范的类名示例: twisted.spread.pb.ViewPoint twisted.parser.patterns.Pattern 下面给出几个不符合上述规范的类名示例: |
|
Line 144: | Line 270: |
应该尽量避免不同模块中的类名之间相互冲突,以减少导入时刻的类名资格检查。例如,一个用于论坛的服务子类可能叫做twisted.forum.service.ForumService,而一个用于word的服务子类可能叫做twisted.words.service.wordsService。这样两个模块中的类名就可以直接导入到用户的命名空间中使用,而不会产生命名冲突,。 | |
Line 146: | Line 271: |
【方法】 方法的命名使用一种混和的拼写方式,方法名的首字母要小写,方法名中除方法名首字母外的每个单词的首字母要大写,用以区分多个单词。例如:someMethodName、method。 有时候,一个类中会给方法起一些专门的名称来做特殊用途,例如:twisted.reflect.Accessor。这种情况下,方法名会有一个小写的单词加上一个下划线作为前缀,于是方法名中就包含了一个下划线,例如:get_someAttribute。因此在Twisted中,带有下划线的方法名可能会具有某些特殊的语义含义。 还有一些方法,典型的就是addCallback及多个相关的函数族,都会返回函数本身,用以支持链式函数调用。这种情况下,请把整个函数调用链用括号括起来,并为每个单独的调用另起一行。例如: ------------------------------------------ | return (foo() | | .addCallback(bar) | | .addCallback(thud) | | .addCallback(wozers)) | ------------------------------------------ 【回调参数】 Twisted中有许多方法,它们的功能就是帮助用户建立回调函数,例如:Deferred.addCallback方法或是reactor的callLater方法。为了作到尽量透明的访问回调函数,大多数的这类方法都会使用**kwargs来扑捉传递给回调函数的所有参数。这使得“建立回调函数”的函数调用看上去非常像是最终要被真正调用的“目标回调函数”。 在这类方法中,要小心防止其它的参数名称覆盖了用户回调函数中的参数。为了保险起见,可以将内部参数的名称前面加上一个下划线作为前缀。例如:RemoteReference.callRemote会被这样调用: ---------------------------------------------------- | myref.callRemote("addUser", "bob", "555-1212") | ---------------------------------------------------- 在remote定义的最后面,下面定义的方法会被调用: ------------------------------ | def addUser(name, phone) | | ... | ------------------------------ 在这里,addUser就是远程方法的名称,用户可能会使用具名参数的方法去执行方法调用: --------------------------------------------------------------- | myref.callRemote("addUser", name="bob", phone="555-1212") | --------------------------------------------------------------- 在这种情况下,callRemote或是其它任何使用了**kwargs语法的代码都要小心,不要使用name,phone或是其它任何可能会覆盖用户提供的具名参数名称的变量名称。因此,callRemote使用下面的实现方式: ---------------------------------------------------- | def callRemote(self, _name, *args, **kwargs) | | ... | ---------------------------------------------------- 应该想尽办法来减少用户使用中可能造成的混淆和冲突。也许,使用assert语句去断言kwargs变量字典中不包含某些可能会产生问题的参数名称是一个恰当的方式。 【特殊方法】 在__iadd__或是其它类似的具名方法中定义的扩展的赋值协议,允许对象做适当的(in place)修改,或是为immutable对象重新绑定名称。上述两种操作都使用相同的操作符。这会导致代码混乱,语义不清,进而导致错误代码的产生。由于这个原因,不应该在Twisted中使用扩展的赋值协议。 【函数】 函数的命名规则与方法的命名规则基本相同。 用于相应事件,并完成callback或是errback调用的函数或是方法应该命名为_cbMethodName或是_ebMethodName,用以和一般的函数或方法相区别。 【属性】 属性的命名规则与函数和方法类似。属性的名称应该是描述式的。通常来说,将属性命名为mode、type或是buf并不能明确说明问题。因此,最好使用displayMode、playerType或是inputBuffer这样的名称来命名属性。 不要使用Python中的私有属性语法,而应该在非共有属性前加上单下划线作为前缀。因为Twisted中有很多同名的类,因此只能通过他们所在的包来区分他们,所以在某些情况下Python的双下划线name-mangle机制并不能可靠。而且在单元测试和类的持久化操作时,通过name-mangle获得的私有变量也难于定位。 当下面的一个或多个条件成立时,一个属性(函数、方法或是类)应该被认为是私有的: o 属性用来表示某种中间状态,但该属性并不会时刻保持最新状态 o 参考该属性的内容或是维护该属性的一个引用可能会导致资源泄漏 o 为该属性赋值可能会破坏某些内部假设 o 该属性是一个known-to-be-sub-optimal接口的一部分,并注定会从今后的版本中去掉。 【数据库】 数据库的表会使用名词的复数形式命名。 数据库的列会使用下划线分隔多个单词,全部列名小写,因为大多数的数据库对列名是不区分大小写的。 任何直接对应于数据库的一个列的属性、方法参数、或是方法名称都应该使用与列相同的命名方式。这种情况下,无需考虑其它的命名方式。 所有的SQL关键字都应该大写。 【C代码】 无论什么情况下,使用C代码来实现都是一种可选的方案,而Python的实现才是默认的,两者应该相互配合。 |
= 类(Classes) = 类的命名使用一种混和的拼写方式,类名的首字母要大写,类名中的每个单词的首字母也要大写,用以区分多个单词。如果类名是一些单词的首字母缩写,则所有字母都要大写。类名不需要使用其所在模块的名称作为类名前缀。下面给出了几个符合上述规范的类名示例: Classes are to be named in mixed case, with the first letter capitalized; each word separated by having its first letter capitalized. Acronyms should be capitalized in their entirety. Class names should not be prefixed with the name of the module they are in. Examples of classes meeting this criteria: {{{ twisted.spread.pb.ViewPoint twisted.parser.patterns.Pattern }}} 下面给出几个不符合上述规范的类名示例: Examples of classes not meeting this criteria: {{{ event.EventHandler main.MainGadget }}} 应该尽量避免不同模块中的类名之间相互冲突,以减少导入时刻的类名资格检查。例如,一个用于论坛的服务子类可能叫做twisted.forum.service.ForumService,而一个用于word的服务子类可能叫做twisted.words.service.wordsService。这样两个模块中的类名就可以直接导入到用户的命名空间中使用,而不会产生命名冲突,。 An effort should be made to prevent class names from clashing with each other between modules, to reduce the need for qualification when importing. For example, a Service subclass for Forums might be named twisted.forum.service.ForumService, and a Service subclass for Words might be twisted.words.service.WordsService. Since neither of these modules are volatile (see above) the classes may be imported directly into the user's namespace and not cause confusion. = 方法(Methods) = 方法的命名使用一种混和的拼写方式,方法名的首字母要小写,方法名中除方法名首字母外的每个单词的首字母要大写,用以区分多个单词。例如:someMethodName、method。 Methods should be in mixed case, with the first letter lower case, each word separated by having its first letter capitalized. For example, someMethodName, method. 有时候,一个类中会给方法起一些专门的名称来做特殊用途,例如:twisted.reflect.Accessor。这种情况下,方法名会有一个小写的单词加上一个下划线作为前缀,于是方法名中就包含了一个下划线,例如:get_someAttribute。因此在Twisted中,带有下划线的方法名可能会具有某些特殊的语义含义。 Sometimes, a class will dispatch to a specialized sort of method using its name; for example, twisted.reflect.Accessor. In those cases, the type of method should be a prefix in all lower-case with a trailing underscore, so method names will have an underscore in them. For example, get_someAttribute. Underscores in method names in twisted code are therefore expected to have some semantic associated with them. 还有一些方法,典型的就是addCallback及多个相关的函数族,都会返回函数本身,用以支持链式函数调用。这种情况下,请把整个函数调用链用括号括起来,并为每个单独的调用另起一行。例如: Some methods, in particular addCallback and its cousins return self to allow for chaining calls. In this case, wrap the chain in parenthesis, and start each chained call on a separate line, for example: {{{ return (foo() .addCallback(bar) .addCallback(thud) .addCallback(wozers)) }}} |
在这里编辑"PyTwisted/WorkingOnTheTwistedCodeBase/CodingStandard".
Twisted编码标准 (Twisted Coding Standard)
命名(Naming)
应该选择一个容易记又有具体含义的名字。模块的命名可以随意一些(例如 twisted.spread ...),但是类命名必须十分清晰明了。写代码的时候请保证手边就有字典或是辞典,方便随时查看。
Try to choose names which are both easy to remember and meaningful. Some silliness is OK at the module naming level (see twisted.spread...) but when choosing class names, be as precise as possible. Write code with a dictionary and thesaurus open on the table next to you.
应该避免用一个术语表示多种含义。要避免这个问题比想象中难的多,因为大多数常用的单词已经被许多其它软件用过了,所以这个规则经常被破坏。更重要的是,应该避免使用那些没有任何意义的单词。特别是像handler、processor、engine、manager和component这些词,这些词只能说明某个东西确实能做一些事情,但是并不能真的表述出这个东西的实际功能,
Try to avoid overloaded terms. This rule is often broken, since it is incredibly difficult, as most normal words have already been taken by some other software. More importantly, try to avoid meaningless words. In particular, words like handler, processor, engine, manager and component don't really indicate what something does, only that it does something.
在命名和python的doc字串请使用美式拼写方法。例如,对于像filesystem这样的合成技术名词,在编码和doc字串中都应该使用没有连字符的拼写方式,以避免不必要的单词首字母大写问题。
Use American spelling in both names and docstrings. For compound technical terms such as 'filesystem', use a non-hyphenated spelling in both docstrings and code in order to avoid unnecessary capitalization.
测试(Testing)
单元测试应该使用twisted.trial框架编写。twisted.test包中有许多例子可以参考。测试模块的名称应该以“test_”开头。每个源码文件中都应该有一个“test-case-name”标签来指定与之相关的测试代码。
Unit tests are written using the twisted.trial framework. Many examples are in the twisted.test package. Test modules should start with 'test_' in their name. Source files should have test-case-name tags that point to their related tests.
验收测试(acceptance test)现在全部由admin/accepttests中的脚本自动完成。(TODO: 真正的验收测试策略)
Acceptance tests are all automated by the admin/accepttests script currently. (TODO: real acceptance tests strategy!)
在你checkin任何修改之前,请运行单元测试来测试你的代码。
Run the unit tests tests before you check anything in.
再次重申,在你checkin任何修改之前,请运行单元测试来测试你代码。由于验收测试通常是不可移植的,并且在某些情况下验收测试自身的运行也会出错,所以出现破坏功能约束的代码这种事儿也是不可避免的,我们也能理解,也可以原谅的。但如果不进行验收测试就提交代码,并造成了对原有功能的损害,就可能会导致从“大家对你的代码所造成的破坏的无情嘲弄”到“取消你在cvs上的commit权限”等各种后果。
Let me repeat that, for emphasis: run the unit tests before you check anything in. Code which breaks functionality is unfortunate and unavoidable. The acceptance tests are highly nonportable and sometimes a pain to run, so this is pardonable. Code which breaks the unit tests in a way that you could have prevented by running them yourself, however, may be grounds for anything from merciless taunting through revertion of the breakage to revocation of cvs commit privileges.
强烈建议开发者学会使用Emacs,并在Emacs中把TwistedEmacs包中的twisted-dev.el文件与F9绑定在一起用来运行单元测试。其它编辑器中现在还没有做类似的支持,但是如果您确实有需要,我们很乐意提供给你。
It is strongly suggested that developers learn to use Emacs, and use the twisted-dev.el file included in the TwistedEmacs package to bind the F9 key to run unit tests and bang on it frequently. Support for other editors is unavailable at this time but we would love to provide it.
如果你修改或是撰写了一个新的HOWTO文档,请参考Lore documentation来学习文档的编写格式。
If you modify, or write a new, HOWTO, please read the Lore documentation to learn the format the docs.
空白缩进(Whitespace)
每个缩进的大小为4个空格键,不允许使用Tab键。强烈建议为每个代码段另起一行,这使代码中的控制结构的缩进更清晰。
Indentation is 4 spaces per indent. Tabs are not allowed. It is preferred that every block appear on a new line, so that control structure indentation is always visible.
模块(Modules)
模块的名称全部小写,并尽可短,最好是一个单词。如果模块的名称包含多个单词,可以使用下划线分隔或是直接将几个单词连起来写。
Modules must be named in all lower-case, preferably short, single words. If a module name contains multiple words, they may be separated by underscores or not separated at all.
大多数情况下,模块应该包含多个类,函数或是方法。如果一个模块只包含一个对象,可以考虑通过代码重构将一些相关的功能包含的该模块中。
In most cases, modules should contain more than one class, function, or method; if a module contains only one object, consider refactoring to include more related functionality in that module.
根据具体情况,下面的几种import方式都是可以的:
Depending on the situation, it is acceptable to have imports that look like this:
from twisted.internet.defer import Deferred
或是:
or like this:
from twisted.internet import defer
也就是说,可以通过from ... import语句来导入module、class和function,但是不能通过from ... import语句导入一个package。
That is, modules should import modules or classes and functions, but not packages.
包(Packages)
包的命名规则与模块大体相同。所有的模块都要封装在某包中。嵌套的包可以用来进一步组织相关的模块。
Package names should follow the same conventions as module names. All modules must be encapsulated in some package. Nested packages may be used to further organize related modules.
init.py文件中除了doc信息和一个可选的all属性之外,不能包含任何其它的东西。包和模块是不同的东西,应该区别对待。但是在代码重构中,如果一个模块被用来构造一个嵌套包中的一部分时,为了保证向后兼容,则不得不破坏这个规则。
init.py must never contain anything other than a docstring and (optionally) an all attribute. Packages are not modules and should be treated differently. This rule may be broken to preserve backwards compatibility if a module is made into a nested package as part of a refactoring.
如果你想把一个模块升级为一个包(例如:为了将一个很大的模块分隔为多个较小的文件),使用“导入模块”进行升级是一个较好的方法,下面是一个例子:
If you wish to promote code from a module to a package, for example, to break a large module out into several smaller files, the accepted way to do this is to promote from within the module. For example,
# parent/ # --- __init__.py --- import child
# --- child.py --- import parent class Foo: pass parent.Foo = Foo
每个包都应该放到setup.py的列表中。
Every package should be added to the list in setup.py.
多个包之间不可以有循环依赖。为了简化维护工作,两个不同的包之间不应该同时进行相互导入。在Twisted中,所有的包都遵循上述约定。应该特别注意一个名为twisted.python的包,要保证这个包不能与Twisted中任何一个其它的包产生依赖关系。
Packages must not depend circularly upon each other. To simplify maintaining this state, packages must also not import each other circularly. While this applies to all packages within Twisted, one twisted.python deserves particular attention, as it may not depend on any other Twisted package.
doc文档(Docstrings)
只要条件允许,就应该使用doc文档来描述python中的方法、函数、类和模块的功能信息。如果某些时候需要完全避免文档描述信息(例如,一个还在开发阶段的接口),可以插入一个doc文档的占位符(例如:“UNDOCUMENT”就不错,_)。这样就不会错误地将其它无用注释作为该方法、函数、类或是模块的doc文档信息,包含到那些自动产生的API文档中。
Wherever possible, docstrings should be used to describe the purpose of methods, functions, classes, and modules. In cases where it's desirable to avoid documenting thoroughly -- for example, and evolving interface -- insert a placeholder docstring ("UNDOCUMENTED" is preferred), so that the auto-generated API documentation will not pick up an extraneous comment as the documentation for that module/class/function.
doc文档从不用来提供一个对象语义信息。如果这些代码将用于一个确实有这样需求的系统中(例如:Zope),可能会违反这个规则。
Docstrings are never to be used to provide semantic information about an object; this rule may be violated if the code in question is to be used in a system where this is a requirement (such as Zope).
doc文档应该与它所描述的代码具有相同的缩进级别。
Docstrings should be indented to the level of the code they are documenting.
doc文档应该用三个双引号开头。
Docstrings should be triple-quoted.
doc文档用epytext格式书写,更多的信息请参考Epytext Markup Language document。
Docstrings should be written in epytext format; more documentation is available in the Epytext Markup Language documentation.
此外,建议Emacs的用户:
Additionally, to accommodate emacs users:
- doc文档中的单引号应该使用其转义形式书写,以防止Emacs将文件中的其它部分误认为是一个String
- Single quotes of the type of the docstring's triple-quote should be escaped. This will prevent font-lock from accidentally fontifying large portions of the file as a string.
- doc文档中的代码示例应该用|开头,以防止IM-Python将doc文档中的示例代码当作真正的代码
- Code examples in docstrings should be prefixed by the | character. This will prevent IM-Python from regarding sample code as real functions, methods, and classes.
例如:
For example,
def foo2bar(f): """I am a function to convert foos to bars. I should be used when you have a foo but you want a bar; note that this is a non-destructive operation. If I can\'t convert the foo to a bar I will raise a FooException(). For example:: | import wombat | def sample(something): | f = something.getFoo() | f.doFooThing() | b = wombat.foo2bar(f) | b.doBarThing() | return b """ # Optionally, actual code can go here.
def foo2bar(f): """这个函数用来将foo转换为bar。 当你有一个foo,但是你想要一个bar的时候,可以使用这个函数; 注意这是一个没有破坏性的操作。如果无法(can\'t)将foo转换为bar, 就会产生一个FooException异常。 例如: | import wombat | def sample(something): | f = something.getFoo() | f.doFooThing() | b = wombat.foo2bar() | b.doBarThing() | return b """ # 实际的代码从这里开始
脚本(Scripts)
对于你想让一个Twisted用户通过命令行来执行的每个脚本,都必须做下面的事儿:
- For each script, that is, a program you expect a Twisted user to run from the command-line, the following things must be done: 在twisted.scripts中编写一个模块,其中包含一个名为run的可调用的全局函数。这个函数会通过不带参数的命令行方式被调用(通常使用sys.argv读取)。如果你认为对其他人有用处,可以在自己的模块中随意添加函数和类供别人使用。 Write a module in twisted.scripts which contains a callable global named run. This will be called by the command line part with no arguments (it will usually read sys.argv). Feel free to write more functions or classes in this module, if you feel they are useful to others. 在bin/目录下编写一个文件,其中包含Twisted的running-from-CVS的头部,并以下面的语句结尾。 Write a file in bin/ which contains the Twisted running-from-CVS header, and ending with
from twisted.scripts.yourmodule import run run()
在doc/man中编写对应的manpage。在debian系统中,你可以找到一个manpage的结构示例,它保存在/usr/share/doc/man-db/examples/manpage.example中。
Write a manpage in doc/man. On debian systems you can find a skeleton example of a manpage in /usr/share/doc/man-db/examples/manpage.example.
把你的脚本添加到setup.py中的脚本列表中。
Add your script to the script list in setup.py.
上面的步骤将确保你的程序能够正确的工作在CVS、Windows和Debian等环境中。
This will insure your program will work correctly for users of CVS, Windows releases and Debian packages.
标准库扩展模块(Standard Library Extension Modules)
当使用一个Python中已有模块的新的扩展版本时,请将import语句放到try/except块中,当import扩展模块失败时,可以import原有Python中的对应模块。这样你的代码就能在没有扩展库支持的平台上维持运行了。例如:
When using the extension version of a module for which there is also a Python version, place the import statement inside a try/except block, and import the Python version if the import fails. This allows code to work on platforms where the extension version is not available. For example:
try: import cPickle as pickle except ImportError: import pickle
使用import语句中的as语法,将扩展模块的名字重新设成与Python中原有模块同名,以覆盖原有的模块。
Use the "as" syntax of the import statement as well, to set the name of the extension module to the name of the Python module.
变更日志(ChangeLog)
所有能够影响最终用户使用Twisted方式的变更都要以一个恰当的方式记录在变更日志中,并记录所有的影响。
All changes that will affect the way end-users see Twisted should come with an appropriate entry in the ChangeLog that summarizes that impact.
变更日志的正确格式是GNU的changelog格式。Emacs有个专门的模式用来编辑GNU changelog格式的文件,可以使用M-x来增加一个变更日志项。无论处于何种荒谬可笑的理由,如果你正在使用一个Emacs以外的编辑器编辑Twisted代码,你可以使用Moshe Zadka提供的admin/change脚本来添加一个符合格式要求的日志项。
The correct format for the ChangeLog is GNU changelog format. There is an emacs mode for editing this, use M-x add-change-log-entry. If you are, for whatever absurd reason, using an editor other than emacs to edit Twisted, you can use Moshe Zadka's helpfully provided admin/change script to add a properly-formatted entry.
event.EventHandler main.MainGadget
类(Classes)
类的命名使用一种混和的拼写方式,类名的首字母要大写,类名中的每个单词的首字母也要大写,用以区分多个单词。如果类名是一些单词的首字母缩写,则所有字母都要大写。类名不需要使用其所在模块的名称作为类名前缀。下面给出了几个符合上述规范的类名示例:
Classes are to be named in mixed case, with the first letter capitalized; each word separated by having its first letter capitalized. Acronyms should be capitalized in their entirety. Class names should not be prefixed with the name of the module they are in. Examples of classes meeting this criteria:
twisted.spread.pb.ViewPoint twisted.parser.patterns.Pattern
下面给出几个不符合上述规范的类名示例:
Examples of classes not meeting this criteria:
event.EventHandler main.MainGadget
应该尽量避免不同模块中的类名之间相互冲突,以减少导入时刻的类名资格检查。例如,一个用于论坛的服务子类可能叫做twisted.forum.service.ForumService,而一个用于word的服务子类可能叫做twisted.words.service.wordsService。这样两个模块中的类名就可以直接导入到用户的命名空间中使用,而不会产生命名冲突,。
An effort should be made to prevent class names from clashing with each other between modules, to reduce the need for qualification when importing. For example, a Service subclass for Forums might be named twisted.forum.service.ForumService, and a Service subclass for Words might be twisted.words.service.WordsService. Since neither of these modules are volatile (see above) the classes may be imported directly into the user's namespace and not cause confusion.
方法(Methods)
方法的命名使用一种混和的拼写方式,方法名的首字母要小写,方法名中除方法名首字母外的每个单词的首字母要大写,用以区分多个单词。例如:someMethodName、method。
Methods should be in mixed case, with the first letter lower case, each word separated by having its first letter capitalized. For example, someMethodName, method.
有时候,一个类中会给方法起一些专门的名称来做特殊用途,例如:twisted.reflect.Accessor。这种情况下,方法名会有一个小写的单词加上一个下划线作为前缀,于是方法名中就包含了一个下划线,例如:get_someAttribute。因此在Twisted中,带有下划线的方法名可能会具有某些特殊的语义含义。
Sometimes, a class will dispatch to a specialized sort of method using its name; for example, twisted.reflect.Accessor. In those cases, the type of method should be a prefix in all lower-case with a trailing underscore, so method names will have an underscore in them. For example, get_someAttribute. Underscores in method names in twisted code are therefore expected to have some semantic associated with them.
还有一些方法,典型的就是addCallback及多个相关的函数族,都会返回函数本身,用以支持链式函数调用。这种情况下,请把整个函数调用链用括号括起来,并为每个单独的调用另起一行。例如:
Some methods, in particular addCallback and its cousins return self to allow for chaining calls. In this case, wrap the chain in parenthesis, and start each chained call on a separate line, for example:
return (foo() .addCallback(bar) .addCallback(thud) .addCallback(wozers))