最佳实践
对于一个新的开发者,写自己的python脚本很容易,但是你也可能养成奇怪的习惯或者写出别人难以理解的代码。对于你自己看当然没问题,但是如果你想和其他人合作或者将你的工作发布到blender,这就需要我们推荐的实践。
风格习惯
对于blender-python开发,按照我们推荐的python风格,避免使用混合的风格,方便你从其他几个工程使用脚本,并将你的脚本共享给blender社区
一个简单的标准罗列如下:
1. 类名大写字母:MyClass
2. 下划线区分开模块名:my_module
3. 四个空格代替tab
4. 操作符左右空格
5. 导入模块必须明确模块名,不能用*代替
6. 不要凑在一行写:if val:body,要分为两行
另外还有:
单引号用于枚举,双引号用于字符串
bpy.context.scene.render.image_settings.file_format ='PNG'
bpy.context.scene.render.filepath="//render_out"
7. 一行不能超过79个字符
#<pep8 compliant>
行长度检查
#<pep8-80compliant>
用户界面布局
写ui布局的一些注意事项:
l UI代码非常简单,布局描述容易建立一个合宜的布局,如果需要对布局描述做更多的代码,对于实际的属性,你做错了
布局例子:
l layout()
基本的布局是简单的自顶向下的布局模式
layout.prop()
layout.prop()
l layout.row()
使用row(),当你需要一行中多个属性时
row =layout.row()
row.prop()
row.prop()
l layout.colum()
使用colum(),当你需要一列中多个属性时
col =layout.column()
col.prop()
col.prop()
l layout.split()
这可以创建更加复杂的布局,例如你需要分隔布局,创建两列布局,当你需要在一行中多个属性的时候,不需要分隔
split =layout.split()
col =split.column()
col.prop()
col.prop()
col =split.column()
col.prop()
col.prop()
描述名字:仅使用以下变量描述布局:
- row for a row() layout
- col for a column() layout
- split for a split() layout
- flow for a column_flow() layout
- sub for a sub layout (a column inside a column for example)
脚本效率
操作列表(通用python建议)
列表元素搜索
列表处理函数,即使不循环,也应该意识到避免列表搜索时代码效率降低
my_list.count(list_item)
my_list.index(list_item)
my_list.remove(list_item)
if list_item in my_list: ...
修改列表
从列表添加和删除,列表长度被修改,尤其是在列表头添加和删除,其后的每一个数据都要更改下标。
在列表后面追加:my_list.append(list_item)或my_list.extend(some_list)
删除元素最好的方式是my_list.pop()或del my_list[-1]
应用索引添加删除的方式是:my_list.insert(index,list_item)或list.pop(index)但是这个效率很低,但是在重建列表更快,但是内存空间需要更多
删除列表中三角形面,不能使用:
faces =mesh.tessfaces[:] # make a list copy of the meshes faces
f_idx =len(faces) # Loop backwards
while f_idx: # while the value is not 0
f_idx -=1
iflen(faces[f_idx].vertices)==3:
faces.pop(f_idx) # remove thetriangle
构建一个新列表更快的方式是:
faces = [f for f in mesh.tessfacesiflen(f.vertices) !=3]
增加列表元素
在一个列表后加另一个列表,不是使用:
for l in some_list:
my_list.append(l)
应该使用:
my_list.extend([a,b, c...])
注意insert可以使用,但是比append慢,尤其是在长列表表头添加元素
以下列表是以次优的方式反转列表:
reverse_list = []
for list_item in some_list:
reverse_list.insert(0,list_item)
Python提更优的方式来反转列表,使用切片方式:
some_reversed_list =some_list[::-1]
删除列表元素
使用my_list.pop(index)而不是my_list.remove(list_item),这需要列表索引,但是比remove()函数更快,因为remove需要搜索整个列表
以下是一个例子,用一个循环删除元素,首先删除最后一个元素会更快:
list_index =len(my_list)
while list_index:
list_index -=1
if my_list[list_index].some_test_attribute==1:
my_list.pop(list_index)
下面的例子更快的方式删除元素,你可以改变列表顺序而不打破脚本功能。这种方法就是交换列表中两个位置,你删除的元素总是最好的。
pop_index =5
# swap so the pop_index is last.
my_list[-1], my_list[pop_index] = my_list[pop_index], my_list[-1]
# remove last item (pop_index)
my_list.pop()
删除许多元素时候这个速度很快
避免删除元素
当函数参数传递一个列表的时候,让函数修改列表更快,而不是返回一个新的列表,这样python不需要删除内存中的列表,修改列表的函数比函数中创建新的列表更高效
慢的:
>>> my_list = some_list_func(my_list)
以下更快,因为没有重布置没有列表复制:
some_list_func(vec)
注意传递分片也会复制到内存中
>>> foobar(my_list[:])
如果有10000个元素,这会消耗很多内存
向文件中写入字符串
以下是三种方式将多个字符串连成一个字符串的方法,这可以用于你代码中的各个区域,牵涉到很多字符串连接。
Python的字符串加载不能用,尤其是在循环中
>>> file.write(str1 +" "+ str2 +" "+ str3 +"\n")
字符串格式转化,当你写字符串数据从float和in时候使用
>>> file.write("%s%s%s\n"% (str1, str2,str3))
Python的字符串连接函数,连接字符串的列表
>>> file.write(" ".join([str1, str2,str3, "\n"]))
很多字符串连接join最快,格式转化最快,字符串算法(loop)是最慢的
字符串解析(导入/导出)
很多文件格式是ASCII,解析或导出字符串在速度上很多区别,有很多解析字符串方法,当导入到blender。
解析数字
float(string)而不是eval(string),int(string),float()也可以用于int,但是用int()更快
检查字符串开始/结束
如果检查字符串开始的关键词,不用:
>>> if line[0:5] =="vert ": ...
使用:
>>> if line.startswith("vert "):
使用startswith()函数更快,大约提速5%,也避免分片长度与字符串长度不匹配而可能的错误
my_string.endswith(“foo_bar”)可以用于行的结尾
如果不确定大小写,要使用lower()和upper()函数
>>> if line.lower().startswith("vert ")
保守使用try/except
try对于检查代码很有用,但是当exception每次被设置时使用try特别慢,所以执行循环或运行多次时中避免使用try
当然也有用try的更快的时候,所以值得一试
数值比较
Python中有两种方式来比较两个数值,a==b和a is b,区别是==可能会运行比较函数__cmp__();但是is则是比较空格,所有的变量都引用同样的内存
如果你检查同样的数据被多个地方引用的时候,is更快
给你的代码计时
计时很有用:
importtime
time_start =time.time()
# do something...
print("MyScript Finished: %.4f sec"% time.time()- time_start)