zoukankan      html  css  js  c++  java
  • 五、上手小操作

    Best Practice

      在编写自己的脚本时,python对于新开发人员来说是非常有用的,但是您也容易养成一些奇怪的习惯,或者编写一些不容易理解的脚本。

      对于你自己的工作,这当然很好,但是如果你想和其他人合作,或者把你的工作包括在blender中,我们会鼓励你进行一些练习。

    1  Style Conventions  风格惯例

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

      如果你想对Blender做贡献的话,那么遵循我们的建议就会变得很容易。

      我们遵循pep8 的编码风格,可以在这里找到here,下面是一个简洁的pep8标准列表:

    • camel caps(类名使用驼峰大小写): MyClass
    • 使用小写下划线分隔模块名: my_module
    • 使用四个空格缩进 (不要使用tabs)
    • 运算符前后加空格. 1, not 1+1
    • 只使用明确的模块导入, (no importing *)
    • 不要在一行里编代码: if val: body, separate onto 2 lines instead.

      除了pep8,我们还有其他用于blender python脚本的约定:

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

      两者都是字符串,但在我们的内部API中,枚举是来自有限集合的惟一项。 eg.

      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>

    2  User Interface Layout  用户界面布局

      在编写UI布局时要记住一些要点:

    • UI 代码非常简单. 布局声明可以很容易地创建一个合适的布局。

      大体规则是: 不要让布局声明的代码多于你实际要操作属性的代码.

    布局例子:

    • layout()

      基本的布局是从上到下Top -> Bottom.

      layout.prop()
      layout.prop()
    • layout.row()

      你想在一行中排列多个属性,使用row().

      row = layout.row()
      row.prop()
      row.prop()
    • layout.column()

      Use column(), 将属性按列排.

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

      这可以创建一些复杂的布局. 例如,你可以将当前布局分割成两个紧挨着的列. 如果你只想排列两个属性时,不要使用split() 而是用 row() 

      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)

    3  Script Efficiency  高效的脚本

    3.1  List Manipulation (General Python Tips)  列表操作

    3.1.1 Searching for list items  查找

      在Python中,有一些方便的列表函数可以帮助您在列表中搜索。

      即使你没有遍历列表,但这其实是Python在帮你做。 因此你要意识到这会降低你的脚本效率。

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

    3.1.2 Modifying Lists  修改

      在Python中我们可以对列表进行添加和删除操作,但当列表长度改变时,这些操作是非常慢的。尤其是列表开始的元素,这样后续的每个元素索引都要改变。

      向列表末尾添加 my_list.append(list_item) or my_list.extend(some_list) 并且快速删除列表末尾的方法是 my_list.pop() or del my_list[-1].

      使用索引你可以my_list.insert(index, list_item) or 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
    
        if len(faces[f_idx].vertices) == 3:
            faces.pop(f_idx)  # remove the triangle
      相比之下使用列表推导新建一个列表会更快:
    faces = [f for f in mesh.tessfaces if len(f.vertices) != 3]

    3.1.3 Adding List Items  添加

      如果想合并两个列表,不要用下面这个

    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使用切片操作来提供更简便的操作,但你可能需要花点时间掌握它,一旦你掌握它 你就会非常依赖它:

    some_reversed_list = some_list[::-1]

    3.1.4 Removing List Items  删除

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

      这要求你有元素的索引,但是更快。因为remove() 会搜索整个列表

      下面这个例子说明了 remove将在一个循环中进行操作, 然后pop一个元素,这就是上面解释了为什么pop删除更快。

    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()

      当在一个长列表中删除时,这会有很好的速度。

    3.1.5 Avoid Copying Lists  避免复制

      当向一个函数传递 list/dictionary, 直接对列表进行操作要比返回一个新的列表快的多,因为这样Python不需要在内存中复制一份参数.

      修改列表的函数比创建新列表的函数更有效

      下面这个很慢,只有在不修改列表时才使用。

    >>> my_list = some_list_func(my_list)

      而下面这个就很快,因为没有重新分配内存并且没有复制操作

    >>> some_list_func(vec)

      还要注意,通过切片列表会复制python内存中的列表。

    >>> foobar(my_list[:])

      如果 my_list 包含10000个元素, 复制它将会消耗很多额外的内存.

    3.2  Writing Strings to a File (Python General)  将字符串写入文件

      这里有三种方法可以将多个字符串连接到一个字符串中。 这也适用于代码中涉及大量字符串连接的任何领域。

      String addition - 这是最慢的, 不要使用它 尤其是在循环中写入数据时.

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

      String formatting -当你要把浮点和整形数写入字符串时,用这个方法。

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

      String join() function用于加入字符串列表 (可以是一个临时列表). 下面这个例子在字符串间添加了” ”,也可以添加 “” or ”, ”.

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

      Join 在多个字符串间操作很快, string formatting 也很快 (尤其在转换数据类型时). String arithmetic 最慢.

    3.3  Parsing Strings (Import/Exporting)  解析字符串

      由于许多文件格式都是ASCII格式的,所以解析/导出字符串的方式会对脚本运行的速度产生很大的影响。

      在将字符串导入Blender时,有一些方法可以解析字符串。

    3.3.1 Parsing Numbers  解析数据

      使用float(string)而不是eval(string),如果知道值将是int(string),float()也会为int工作,但是使用int()读取ints更快。

    3.3.2 Checking String Start/End

      如果你要检查某个字符串是不是以某个关键字开头,不要这样操作...

    >>> if line[0:5] == "vert ": ...

      而是...

    >>> if line.startswith("vert "):

      使用startswith() 会稍微更快 (approx 5%) and也避免了切片的长度与字符串长度不匹配的问题.

      my_string.endswith(“foo_bar”) 也可以用来检查字符串的结尾.

      如果不确定字母大小写, use the lower() or upper() string function.

    >>> if line.lower().startswith("vert ")

    3.4  Use try/except Sparingly 少量使用异常检查

      try语句有助于节省编写错误检查代码的时间。

      但是,如果每次都必须设置一个异常,那么try要明显慢一些,所以要避免在代码中执行多次循环并运行的区域使用try。

      有些情况下,使用try比检查条件是否引起错误要快,所以这是值得尝试的。

    3.5  Value Comparison  值比较

      Python有两种方法来比较值a == b和a is b,不同的是= =可以运行对象比较函数__cmp__(),而is比较标识,这两个变量在内存中引用相同的项。

      如果您知道您正在检查从多个地方引用的相同值,则 is 更快。

    3.6  Time Your Code  检测你代码的性能

      在开发脚本时,最好能让它意识到性能上的任何变化,这可以简单地完成。

    import time
    time_start = time.time()
    
    # do something...
    
    print("My Script Finished: %.4f sec" % (time.time() - time_start))
  • 相关阅读:
    java线程小结1
    String和StringBuffer
    java队列的实现
    java栈的实现
    java链表
    this与super关键字总结
    JVM内存杂记1
    面试题18:删除链表节点
    面试题17:打印从 1 到最大的 n 位数
    面试题16:数值的整数次方
  • 原文地址:https://www.cnblogs.com/wildbloom/p/7756780.html
Copyright © 2011-2022 走看看