基础命令
# 更新 pip
python -m pip install --upgrade pip
# 使用国内镜像提高库安装速度
pip install name -i https://pypi.tuna.tsinghua.edu.cn/simple
# 清华大学:https://pypi.tuna.tsinghua.edu.cn/simple
# 阿里云:https://mirrors.aliyun.com/pypi/simple/
# 中国科学技术大学:https://pypi.mirrors.ustc.edu.cn/simple/
# 批量安装库
pip install -r requirements.txt
# 创建虚拟环境
python -m venv my_project_env
# 激活虚拟环境
my_project_env\Scripts\activate
Python3
推荐使用Python3而不是Python2,即使使用Python2,也请尽量兼容到Python3,例如:在Python2.x中可以不带括号的print输出log,但是建议使用带括号的,主要是为了兼容Python3.x,推荐做法:
print(xxx)
在Python2中可以使用
Exception, e:
为了兼容Python3,推荐使用:
Exception as e:
听从建议
PyCharm给出的带有下划线的建议,多看看,并根据建议改正。例如Python推荐函数名和变量名是小写,单词中间用下划线分割。类名或文件名最好用大写。如果能够严格跟着做,基本上代码规范上会有很大提升了。
文本格式
新建的Python文件脚本第一行是:
# coding: utf-8
import语句一定是在最前的,作者信息等最好放在import语句后。 例如:
__author__ = 'sing'
# coding: utf-8
import os
可以改为:
# coding: utf-8
import os
__author__ = 'sing'
这个可以在pycharm中设置新建代码模板。
显示声明
Python的变量虽说是无须声明就可以使用,但是代码量一大,变量出现在各个函数中,很容易就跟局部变量弄混,有一个小技巧是在__init__函数中“露个脸”,这样在编写其他函数时就很容易知道该类到底有哪些变量了。类的成员变量的写法上也可以与局部变量有所区别,以免弄混,例如带个下划线的前缀。
class Config:
def __init__(self, jsonFile):
self._inited = None
self._root_dir = None
self._json = None
self._packed_args = None
self._validate_args = None
self._filtered_args = None
self._wrapper_version = None
self._wrap_type = None
self._in_file = None
self._jar_configs = []
self._out_dir = None
self._log = None
self._result_log = None
常量
常量最好都放一个文件里,便于后期维护,否则杂乱地分散在不同的脚本文件中很难找。给一个模板:
# coding:utf-8
class Constant:
@staticmethod
def test():
pass
# xxxx
Constant.VER = "1.0"
使用时:
from Constant import Constant
print Constant.VER
参数解析
请不要自行封装解析函数,现有的三方库完全可以满足需求,没有必须重复造轮子(自己实现可能不太稳定,也很有可能存在BUG),推荐使用:
# coding: utf-8
import argparse
'''
argparse.ArgumentParser在解析参数失败时不是抛出异常,而是直接错误退出。
这里重载掉error函数,抛出异常,使得外层可以捕获该异常并输出参数帮助。
'''
class ArgumentParserError(Exception): pass
class MyArgumentParser(argparse.ArgumentParser):
def error(self, message):
raise ArgumentParserError(message)
使用时:
args = None
parser = MyArgumentParser(description="自动打包发布工具参数说明")
parser.add_argument('key', help="Redis key where items are stored")
parser.add_argument('--file', required=True, help='设置xxx文件路径')
parser.add_argument('--ver', help='设置版本号')
parser.add_argument('--timeout', type=int, default=5)
parser.add_argument('--limit', type=int, default=0)
parser.add_argument('--progress_every', type=int, default=100)
parser.add_argument('-v', '--verbose', action='store_true')
try:
args = parser.parse_args()
except Exception, e:
parser.print_help()
return False
file = args.file
当不明所以的人参数使用错误时输出帮助信息:
usage: Main.py [-h] --file FILE [--ver VER] [--timeout TIMEOUT]
[--limit LIMIT] [--progress_every PROGRESS_EVERY] [-v]
key
自动打包发布工具参数说明
positional arguments:
key Redis key where items are stored
optional arguments:
-h, --help show this help message and exit
--file FILE 设置xxx文件路径
--ver VER 设置版本号
--timeout TIMEOUT
--limit LIMIT
--progress_every PROGRESS_EVERY
-v, --verbose
路径
路径分隔符用os.sep,不要用写死的斜杠字符或反斜杠字符。 路径拼接可以用os.path.join,少用加号(+)拼接。但是os.path.join函数似乎并不完美,第一个参数最好末尾不带斜杠,而第二个参数的第一个字符也不能是斜杠,例如 os.path.join(self._this_path, ‘/test’) 可能会得到一个不存在的路径。 不过在Python3里,路径的操作增加了pathlib 的库,路径拼接可以这么用:
path_pure = pathlib.PurePath('xxxx')
path_pure = path_pure / 'python' / 'hello.py' # 拼接路径
我发现在很多项目里面会使用三方的tool,如何使用这些工具的路径?给一个参考:
#coding:utf-8
import os
import Utils
class _PathManager:
def __init__(self):
self._this_path = Utils.getthispath()
# XXX的路径
def get_test_proj_path(self):
return os.path.join(self._this_path, '.../BestvPlayerSample2')
# XXX的路径
def get_dx_path(self):
return os.path.join(self._this_path, 'tools/dx.jar')
# XXX的路径
def get_wrapper_path(self):
return os.path.join(self._this_path, r'bin/jarwrapper.jar')
# proguardLib路径
def get_proguard_path(self):
return os.path.join(self._this_path, 'tools/proguard5.2.1/lib/proguard.jar')
# 加密dex jar包的路径
def get_cipher_path(self):
return os.path.join(self._this_path, 'tools/encryptDex.jar')
PathManager = _PathManager()
使用时:
from PathManager import *
PathManager.get_test_proj_path()
打开文件
打开文件推荐使用with,最后不用关闭。
with open('foo.txt', 'w') as f:
f.write('hello!')
字符串列表的拼接
s = ["Python", "is", "good"]
# Python is good
res = ' '.join(s)
不优雅的做法:
def get_classes_string(self, class_list):
class_string = ''
for item in class_list:
class_string += item
class_string += ','
return class_string
字典默认值,GET的第二个参数可以设置默认
d = {'key1':1,'key2':"hello"}
# 字段存在没问题
print d['key1'] + 1
print d['key2'] + 'world'
# 字段不存在使用get加默认值不会有异常
print d.get('key3', 0) + 1
print d.get('key4',"") + 'world'
# 字段不存在会产生异常
print d['key3'] + 1
print d['key4'] + 'world'
测试
- 在__main__中写测试代码
- 巧用DEBUG开关:命令行参数没法传到SVN上,使用如下方式可以把DEBUG开关打开,填入测试性的命令行参数,测试完毕后关闭DEBUG开关即可。
DEBUG = True
@logtime(u"SDK加固")
def wrap_sdk(params):
# 初始化日志
initLog(None, False)
# 解析参数
(options, args) = Options.parse(params)
return True
if __name__ == '__main__':
ret = False
try:
if DEBUG:
ret = wrap_sdk([__file__, '--jar=xxxxxx', ''])
else:
ret = wrap_sdk(sys.argv)
if ret is False:
print "failed"
except Exception as e:
print traceback.format_exc()
os.system('pause')
if not ret:
sys.exit(-1)
函数耗时
# 让函数打印耗时
def logtime(name = None):
def wrapper(func):
def wrapper2(*args, **kwargs):
_name = name
if name is None:
_name = func.func_name
else:
_name = name
print(_name + u" start")
startTime = time.time()
res = func(*args, **kwargs)
print(u"%s end, time used: %.1f s" % (_name, time.time() - startTime))
return res
return wrapper2
return wrapper
使用时:
@logtime(u"SDK加固")
def wrap_sdk(params):
pass
路径多用相对路径
考虑到大家是在协同编程,代码需要上传到SVN或Git,有时需要部署到服务器,绝对路径肯定不能适配到每个人,因此要养成尽量多用相对路径的习惯。即使不能直接用相对路径的全路径(例如当前工程目录),也要通过代码调用来动态获取。
流程上的建议
在主流程中处理的各个子节点尽量用logging函数分级打印输出日志,以便日后排错好知道流程走在哪个节点出错的。 如果某个小功能需要输出很多日志,在不出错的情况下可以不用输出,以免淹没其他有用的流程信息,浪费调试时间;在出错的情况下可以输出内部详细日志。 在我们的实际后台页面展示效果上,ERROR类型的日志为高亮的红色,一下子就能看到出错的位置了,排查起来很便捷。
2017-07-14 11:09:46 Main.py [line:278 ] INFO 日志记录启动
2017-07-14 11:09:46 Main.py [line:281 ] INFO 版本号:v1.01
2017-07-14 11:09:46 Main.py [line:284 ] INFO
2017-07-14 11:09:46 Main.py [line:285 ] INFO
2017-07-14 11:09:46 Main.py [line:287 ] INFO 配置解析结果:
2017-07-14 11:09:46 Main.py [line:288 ] INFO ------------------------------------------------------------
2017-07-14 11:09:46 Main.py [line:289 ] INFO
2017-07-14 11:09:46 Main.py [line:290 ] INFO
2017-07-14 11:09:46 Main.py [line:291 ] INFO
2017-07-14 11:09:46 Main.py [line:292 ] INFO
2017-07-14 11:09:46 Main.py [line:293 ] INFO
2017-07-14 11:09:46 Main.py [line:300 ] INFO ------------------------------------------------------------
2017-07-14 11:09:46 Main.py [line:121 ] ERROR [完成]!
脚本模板
打开菜单File > Settting,找到Editor > File and Code Templates,Python Script添加:
# coding: utf-8
import os
import sys
import traceback
DEBUG = True
def main(params):
return True
if __name__ == '__main__':
ret = False
try:
if DEBUG:
ret = main([__file__, '', '']) # 这里在调试状态下可以随意填参数,方便排查问题
else:
ret = main(sys.argv)
if ret is False:
print("failed")
except:
print(traceback.format_exc())
os.system('pause')
函数嵌套层次不要太深
不建议超过五层,太深的层次理解起来太费劲,容易出错也不美观,建议拆分出子模块调用。
文档信息
- 本文作者:zhupite
- 本文链接:https://zhupite.com/python/Python%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83%E5%8F%8A%E5%BB%BA%E8%AE%AE.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)