blender python官网文档译解之最佳实践


类别:3d应用   

发布时间:2019/10/17 16:33:13   更新时间:2020/07/31 19:49:25


本文官网地址:https://docs.blender.org/api/current/info_best_practice.html

本文基于Blender2.80。

提示:译解是指翻译和注解。【注解】是作者的一些个人解释,用【】符号括起来。

 

最佳实践

在编写自己的脚本时,python非常适合新开发人员使用并提高工作效率,但您也可以养成奇怪的习惯,或者至少编写不容易被他人理解的脚本。

对于您自己的工作,这当然很好,但是如果您想与他人合作或将您的工作包含在blender中,我们鼓励您采取一些做法。

样式约定

对于Blender / Python开发,我们选择遵循python建议的样式指南,以避免在我们自己的脚本之间混合样式,并使其更易于使用其他项目中的python脚本。

如果您最终希望将它们添加到Blender中,则将我们的样式指南用于您自己的脚本可以使工作更加轻松。

此样式指南称为pep8,可在此处找到

pep8标准的简短列表。

* 类名称的骆驼帽:MyClass

* 所有小写??的下划线下划线模块名称:my_module

* 缩进4个空格(无制表符)

* 运算符周围的空格。,1 + 1而不是1+1

* 仅使用显式导入(不导入*)

* 不要使用单行:if val: body,而是分成两行。

和pep8一样,我们还有其他用于Blender Python脚本的约定。

* 枚举使用单引号,字符串使用双引号。

两者当然都是字符串,但是在我们内部的API中,枚举是有限集合中的唯一项。例如。

bpy.context.scene.render.image_settings.file_format = 'PNG'
bpy.context.scene.render.filepath = "//render_out"

* pep8还定义了行数不能超过79个字符,我们认为这过于严格,因此每个脚本都是可选的。

我们会定期检查Blender脚本是否符合pep8,对于要包含在此检查中的脚本,请在脚本顶部将该行添加为注释。

# <pep8 compliant>

要启用行长检查,请改用此选项。

# <pep8-80 compliant>

用户界面布局

* 编写UI布局时要记住的一些注意事项:

UI代码非常简单。可以使用布局声明轻松创建体面的布局。

此处的一般规则:如果需要更多的代码用于布局声明,那么对于实际属性,您就做错了。

布局示例:

* layout()

基本布局是简单的Top->Bottom布局。

layout.prop()
layout.prop()

* layout.row()

如果要在一行中包含多个属性,请使用row()。

row = layout.row()
row.prop()
row.prop()

* layout.column()

如果要在列中使用属性,请使用column()。

col = layout.column()
col.prop()
col.prop()

* layout.split()

这可用于创建更复杂的布局。例如,您可以拆分布局并创建两个彼此相邻的column()布局。当您只需要连续两个属性时,请不要使用split。为此使用row()。

split = layout.split()

 
col = split.column()
col.prop()
col.prop()

 
col = split.column()
col.prop()
col.prop()

声明名称:

尝试仅将这些变量名称用于布局声明:

* row()布局的行

* column()布局的列

* 拆分为split()布局

* column_flow()布局的流程

* sub布局(例如,列内的一列)的子布局

脚本效率

列表操作(Python常规技巧)

在搜索列表中的项目

在Python中,有一些方便的列表功能,这些功能使您不必在列表中进行搜索。

即使您没有遍历python所遍历的列表数据,但是您需要注意那些通过搜索整个列表来降低脚本速度的函数。

my_list.count(list_item)
my_list.index(list_item)
my_list.remove(list_item)
if list_item in my_list: ...

修改列表

在python中,我们可以在列表中添加和删除列表,当修改列表长度时,这会比较慢,尤其是在列表的开头,因为修改索引之后的所有数据都需要上移或下移1位。

添加到列表末尾的最简单方法是使用 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)

有时它更快(但需要更多的内存)来重建列表。

假设您要删除列表中的所有三角形多边形。

而不是…

polygons = mesh.polygons[:]  # make a list copy of the meshes polygons
p_idx = len(polygons)     # Loop backwards
while p_idx:           # while the value is not 0
    p_idx -= 1

 
    if len(polygons[p_idx].vertices) == 3:
        polygons.pop(p_idx)  # remove the triangle

使用列表理解来构建新列表更快。

polygons = [p for p in mesh.polygons if len(p.vertices) != 3]

添加列表项

如果您有一个列表要添加到另一个列表,而不是…

for l in some_list:
    my_list.append(l)

采用…

my_list.extend([a, b, c...])

请注意,可以在需要时使用插入,但是它比添加要慢,尤其是在长列表的开头插入时。

此示例显示了制作反向列表的非常次优的方式。

reverse_list = []
for list_item in some_list:
    reverse_list.insert(0, list_item)

Python提供了更方便的方法来使用slice方法来反转列表,但是您可能需要在过多依赖它之前对其进行计时:

some_reversed_list = some_list[::-1]

删除列表项

使用my_list.pop(index)而不是my_list.remove(list_item)

这要求您具有列表项的索引,但是要更快,因为remove()它将搜索列表。

这是一个如何在1个循环中删除项目,如何先删除最后一个项目的示例,这样做速度更快(如上所述)。

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)

此示例显示了一种删除项目的快速方法,用于在不破坏脚本功能的情况下可以更改列表顺序的情况。这可以通过交换2个列表项来实现,因此您删除的项始终是最后一个。

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)

还要注意,传递切片列表会在Python内存中复制列表。

>>> foobar(my_list[:])

如果my_list是一个大型数组,其中包含10000个项目,那么一个副本可能会占用大量额外的内存。

将字符串写入文件(Python常规)

这是将多个字符串连接为一个字符串进行写入的3种方法。这也适用于代码中涉及大量字符串连接的任何区域。

String addition-这是最慢的选项,如果可以帮助不要使用,尤其是在循环写入数据时

>>> file.write(str1 + " " + str2 + " " + str3 + "\n")

String formatting -从浮点数和整数写入字符串数据时,请使用此选项。

>>> file.write("%s %s %s\n" % (str1, str2, str3))

String join() function 用于连接字符串列表(该列表可能是临时的)。在以下示例中,字符串之间使用空格“”连接,其他示例为“”或“,”。

>>> file.write(" ".join([str1, str2, str3, "\n"]))

Join在许多字符串上最快, 字符串格式 也相当快(转换数据类型更好)。字符串算术最慢。

解析字符串(导入/导出)

由于许多文件格式都是ASCII,因此解析/导出字符串的方式可能会极大地影响脚本的运行速度。

将字符串导入Blender时,有几种解析字符串的方法。

解析数

使用float(string)而不是eval(string),如果您知道该值将是一个int,则int(string)float()也会对一个int起作用,但是使用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 /除难溶

尝试语句是有用的,以节省时间编写错误校验码。

但是try的速度比if慢得多,因为每次都必须设置一个异常,因此请避免在循环执行并运行多次的代码区域中使用try

在某些情况下,使用try比检查条件是否会引发错误更快,因此值得尝试。

值比较

Python有两种比较值的方式,和的区别是可以运行对象比较功能,而比较标识,即两个变量都引用内存中的同一项目。a == ba is b==__cmp__()is

如果您知道要检查从多个位置引用的相同值,is则速度会更快。

为您的代码计时

在开发脚本时,最好是及时安排它以了解性能的任何变化,这可以轻松完成。

import time
time_start = time.time()

 
# do something...

 
print("My Script Finished: %.4f sec" % (time.time() - time_start))


本文网址:https://www.pyfield.com/blog/?id=34