python编码及工程规范

1、structuring of project

    首先我们需要去考虑如何更好地利用Python的特性来创造简洁、高效的代码。在C++/Java等工业界的语言中,“结构化”意味着通过编写简洁的代码,正如文件系统中文件和目录的组织一样,使代码的逻辑和依赖更清晰。

在任何项目开始之前我们需要做一个规划,例如哪个函数应该深入到哪个模块,数据在项目中应该如何流转,什么功能和函数应该组合或独立,最终看到的产品是怎样的等

2、structuring of repository

    在一个健康的开发周期中,代码风格,API设计和自动化都是非常关键的,如果目录结构是一团糟,没有清晰的结构,可能需要到处寻找才能找到所需要的内容或文档,为让每一位开发者能够熟悉它的每一个角落和细节,拥有良好的细节,良好的布局将会事半功倍

for example:README.rst
LICENSE-----------------------------在这个文件中要有完整的许可说明和授权。
setup.py-------------------------------  打包和发布管理
requirements.txt---------------------  它应该指明完整工程的所有依赖包: 测试, 编译和文档生成。
scanhosts/__init__.py--------------------------核心代码
scanhosts/views.py
dashboard/views.py
mydevops/settings.py---------------------配置文件
docs/index.rst------------------------参考文档
tests/test_basic.py----------------- 集合与单元测试,应该把测试例子放到模块里面,但这样会增加用户使用的复杂度;而且添加测试模块将导致需要额外的依赖和运行环境。
tests/test_advanced.py

manage.py-------------------------------------------- 常规管理脚本,即使不是C/C++写的项目也有makefile文件,make对于定义常规的管理任务是非常有用的工具

 

3、Django Applications

    不要错误的使用Django自带的应用模板创建项目,而导致目录结构非常糟糕

     通常:django admin.py startproject samplesite

       生成:

README.rst
mydevops/manage.py
mydevops/mydevops/settings.py
mydevops/mydevops/wsgi.py
mydevops/mydevops/scanhosts/models.py

       避免上述类似操作,因为相对路径使girrit工具等及开发者都容易误解,这种没有必要的嵌套对任何人都无益

    正确:django-admin.py startproject samplesite .

    生成:

README.rst
manage.py
samplesite/settings.py
samplesite/wsgi.py
samplesite/sampleapp/models.py

4、modules

    Python的modules是最主要的抽象层之一,抽象层允许将代码分成不同的部分,每个部分包含相关的数据与功能,在项目中,一层控制用户操作的相关接口,另一层处理底层数据的操作。最自然的分开这两层的方式是,在一层文件里重组所有的功能接口,并将所有底层操作封装到另一个文件中,这种情况下,接口文件需要导入封装底层操作的文件,可通过import和from import来完成。

    为遵守QJHK+J02009-2018+Python编程规范,规定模块名称要短、尽量使用小写,并避免使用特殊符号,例如.或?,scanhosts.db.py,该命名方式将会阻碍python的模块查找功能,python将认为需要在scanhosts文件夹中找到db.py,应尽量保持模块名称简单,无需分开单词,不要使用下滑线命名空间,而是使用子模块

# Good
import library.plugin.foo
# Bad
import library.foo_plugin

    除了以上的命名限制外,python文件成为模块没有其他特殊的要求,但为了合理的使用这个观念并避免问题,需要理解import的原理机制。Import module语句将寻找合适的文件,调用目录下的module.py,若没有找到,python解释器将递归的在pythonpath环境变量中查找文件,若仍没有找到,将抛出ImportError异常,一旦找到module.py,python解释器将在隔离的作用域中执行这个模块,所有顶层语句都会执行,包括其他的引用。方法与类的引用将会存储到模块的字典中,然后,这个模块的变量,方法和类通过命名空间暴漏给调用方,这是python中特别有用且核心的概念

5、packages

    Python提供非常简单的包管理系统,即简单地将模块管理机制扩展到一个目录上(目录扩 展为包)。

    任意包含 __init__.py 文件的目录都被认为是一个Python包

   

    一个常见的问题是往 __init__.py 中加了过多代码,随着项目的复杂度增长, 目录结构越来越深,子包和更深嵌套的子包可能会出现。在这种情况下,导入多层嵌套 的子包中的某个部件需要执行所有通过路径里碰到的 __init__.py 文件。如果 包内的模块和子包没有代码共享的需求,使用空白的 __init__.py 文件是正常 甚至好的做法。

6、code style

   我们提倡最明确和最直接的编码方式 

6.1、尽可能使用 is/is not 取代 ‘==’

6.2、使用基于类的异常

6.3、异常中不要裸露except、后面跟上具体的exception

6.4、异常中try代码尽可能少

6.5、python2中十进制浮点精度运算不准确,可使用decimal和fraction模块,例如价格校验

6.6、urlib2多线程访问会死锁,可使用urllib3模块

6.7、避免使用while true,避免死循环

6.8、函数if else不要多于3-4个,保持代码和逻辑清晰,复杂段落每个小的逻辑段落要有空行和注释

6.9、避免使用全局变量

6.10、复合语句因其简洁和表达性受到推崇,但不应同一行代码中写两条独立的语句。

 

7、Python 代码遵循 PEP 8 ,这也有助于在与其他开发人员 一起工作时使代码更加具有可持续性

7.1、检查变量是否等于常量

不需要明确的比较True或None,仅需放在if语句中(尽可能使用is/is not 取代 '==')

bad:

if attr == True:
    print 'True!'

if attr == None:
    print 'attr is None!'

Good:
if attr:
    print 'attr is truthy!'
if not attr:
    print 'attr is falsey!'
# or, since None is considered false, explicitly check for it
if attr is None:
    print 'attr is None!'

7.2、访问字典元素

不要使用 dict.has_key() 方法。取而代之,使用 x in d 语法,或者 将一个默认参数传递给 dict.get()

Bad:

d = {'hello': 'world'}
if d.has_key('hello'):
    print d['hello']    # 打印 'world'
else:
    print 'default_value'

 

Good:

d = {'hello': 'world'}

print d.get('hello', 'default_value') # 打印 'world'
print d.get('thingy', 'default_value') # 打印 'default_value'

# Or:
if 'hello' in d:
    print d['hello']

7.3:过滤列表:

在迭代列表的过程中,永远不要从列表中移除元素

# 过滤大于 4 的元素
a = [3, 4, 5]
for i in a:
    if i > 4:
        a.remove(i)

不要在列表中多次遍历

while i in a:
    a.remove(i)

 

7.4:在列表中修改值

bad:

赋值永远不会创建新对象。如果两个或多个变量引用相同的列表,则修改其中一个变量意味着将修改所有变量

# 所有的列表成员都加 3
a = [3, 4, 5]
b = a                     # a 和 b 都指向一个列表独享

for i in range(len(a)):
    a[i] += 3             # b[i] 也改变了

 

good:

创建一个新的列表对象并保留原始列表对象会更安全

a = [3, 4, 5]
b = a

# 给变量 "a" 赋值新的列表,而不改变 "b"
a = [i + 3 for i in a]
# 或者 (Python 2.x):
a = map(lambda i: i + 3, a)
# 或者 (Python 3.x):
a = list(map(lambda i: i + 3, a))

 

使用 enumerate() 获得列表中的当前位置的计数,

使用 enumerate() 函数比手动维护计数有更好的可读性。而且,它对迭代器 进行了更好的优化

a = [3, 4, 5]
for i, item in enumerate(a):
    print i, item
# 打印
# 0 3
# 1 4
# 2 5

 

读取文件:

使用with open语法来读取文件,它将会为您自动关闭文件

bad:

f = open('file.txt')
a = f.read()
print a
f.close()

 

Good:

with open('file.txt') as f:
    for line in f:
        print line

 

尽量使用with语句,即使是在 with 的区块中抛出异常,也能确保关闭文件。

 

8、Django工程注意规范

8.1.各个APP独立,做到项目的模块分明。 

    from mydevops.scanhosts.models import mycat

    该例子将项目名称加入其中是不合适,缺点在于:应用和项目变成了紧耦合,无法将应用轻易变得可重用。如果将来要换一个项目名称,那你可有得受了。

    推荐的做法是

     from scanhosts.models import mycat

8.2. 不要硬编码 MEDIA_ROOT,STATIS_ROOT, 

    在python中关于url的处理,有些原则,比如不要硬编码,处理成UNIX,WINDOWS兼容的格式,和进行空格的处理等

    MEDIA_ROOT = 'E:\\test\mugshot\\'

     STATIC_ROOT = '/VAR/TEMP/STATIC'

    这种做法有很多问题,比如机器迁移,和 应用的移动都会影响。

    SITE_ROOT = os.path.realpath(os.path.dirname(__file__)) 

     MEDIA_ROOT = os.path.join(SITE_ROOT, 'appmedia') 

     TEMPLATE_DIRS = ( os.path.join(SITE_ROOT, 'templates'),)  

    这样的写法比较可扩展性。

8.3,不要将业务逻辑代码写到视图里

    虽然很多例子,它们把逻辑都写在了views.py里,因为这样不利于单元测试,不利于重用代码。

    那我们的业务逻辑应该放哪里呢?推荐放到模型里或者单独建立一个辅助模块。

    当然,获取数据列表的代码是可以放到视图里面的。

8.4,部署时别忘记将DEBUG设置成False

8.5、合理配置和使用URL

    不要将URL全都配置在一个urls.py文件中,比如:

    urlpatterns = [
    url(r'admin/', admin.site.urls),
    url(r'^getinfos$',user_history),
    url(r'^userinfos$',user_info),  
    url(r'^userauths$',user_auth),
    url(r'^usertemplates$',user_templates),
    url(r'listmycat',list_mycat),
    url(r'^add_mycat$',add_mycat),
    url(r'^add_mycat_monitor$',add_mycat_monitor),
    url(r'^search_datasource$',search_datasource),
    url(r'^create_dashboard$',create_dashboard),
    url(r'^mycat_delete/(?P<id>[0-9]+)/$',views.mycat_delete,name='mycat_delete')
    url(r'^addmycat',mycat_handler)
]

建议的方式是将各应用的URL配置在各自的urls.py中,这样可以使应用更容易重复使用到不同项目里:

urlpatterns = [
url(r'^admin/',admin.site.urls),
url(r'^xadmin/',xadmin.site.urls),
url(r'^DevOps/',include('scanhosts.urls',namespace='scanhosts')),
url(r'^DevOps/',include('grafahosts.urls',namespace='grafahosts')),
url(r'^DevOps/',include('dashboardhosts.urls',namespace='dashboardhosts'))
]

 

9、注释规范:

# status:success/failed
# data:object/string
# errmsg:错误返回的信息,可以直接弹出给用户


def mycat_del(request):
    """
 :param:vip
 :return: 删除成功,已删除mycat的信息
 """
 errmsg = None
 status = "failed"
 context = {
        "status": status,
        "errmsg": errmsg
    }
    if request.method == 'POST':
        vip = request.POST.get('vip').strip()
        if vip is not None:
            try:
                Mycat.objects.filter(vip=vip).update(deleted=0)
            except vip.DoseNotExist:
                context['errmsg'] = "Mycat %s does not exist." % vip
            else:
                context["status"] = "success"

 return JsonResponse(context)

优美胜于丑陋(Python以编写优美的代码为目标)
明了胜于晦涩(优美的代码应当是明了的,命名规范,风格相似)
简洁胜于复杂(优美的代码应当是简洁的,不要有复杂的内部实现)
复杂胜于凌乱(如果复杂不可避免,那代码间也不能有难懂的关系,要保持接口简洁)
扁平胜于嵌套(优美的代码应当是扁平的,不能有太多的嵌套)
间隔胜于紧凑(优美的代码有适当的间隔,不要奢望一行代码解决问题)
可读性很重要(优美的代码是可读的)

 

相关文章

Mycat是什么?MyCat是一个开源的分布式数据库系统,是一个实...
转自:https://www.cnblogs.com/ivictor/p/5111495.html参考...
1.在数据库做好主从同步的情况下搭建mycat。下载mycat,解压...
集群的服务器列表在10.11.0.210和10.11.0.216中部署mycat和h...
Mycat是什么?·一个彻底开源的,面向企业应用开发的大数据库...
<system>配置Mycat系统参数 <system>  <p...