learning python in the motion picture industry by will zhou
DESCRIPTION
2010年公司内部培训教案用TRANSCRIPT
Lesson 1By Will Zhou
简单、易学
Python语言是少有的一种可以称得上即简单又功能强大的编程语言。你将惊喜地发现Python语言是多么地简单,它注重的是如何解决问题而不是编程语言的语法和结构。
免费、开源
你可以获取Python的源代码,对其进行改进。比如Stackless Python,就是修改过的增强版本Python。
高阶语言
高阶语言的一个重要特性就是,你不用顾忌程序在内存上的分配和释放等底层细节。
跨平台、可移植性
你可以在Linux,Windows,Mac OS X和Solaris等操作系统上使用Python,不涉及硬件和系统细节的程序,一般100%兼容。
解释性
与解释语言不同的另外一种语言就是编译语言。编译语言要生成最终可执行代码,需要通过编译器编译;而解释语言则可以通过调用解释器直接执行所编写的代码。
面向对象
面向对象编程,即Object-Oriented Programming,是一种现代化的程序设计方法,大大增加代码的可重复利用性。设计大型程序,必不可少。Python的面向对象实现,有别于C++和Java,它强大且简单。
可扩展性
你可以通过C++来编写核心部分,然后通过Python调用。比如Houdini的_hou.so就是C++开发的Python模块。
可嵌入性
比如Houdini和Nuke支持的Python表达式。
丰富的库
庞大的标准库,还有很多其他高质量的库,几乎应有尽有。
管理文件系统
◦ 深层次结构目录和文件的管理
◦ 用Python实现Job System及相关工具
开发Tactic、Shotgun等流程管理类软件的插件和模块
Qube!、HQueue等渲染农场队列管理工具也集成了Python
扩展MoinMoin Wiki
访问、管理数据库
XLS、CSV等表格处理
HOM – Houdini Object Module
HDA
hou.session
Shelf
Houdini的远程调用方式
◦ RunPythonStatements() 通过Javascript执行XML代码
◦ Houxmlrpc
Hython – 比如我们自己开发的灯光组用渲染命令
SOHO – Scripted Output of Houdini Objects
TCL Expression
[ python {#PYTHON_STATEMENTS#} ]
Rotopaint
用Python来辅助进行Roto工作
Knobs
Toolbars ( menu.py )
init.py
Metadata
Callbacks
Rendering
nuke.execute(―Write1‖, 101, 200, 1)
多多练习
多看代码
学以致用
Ubuntu Linux 下,一般默认就安装好了;
Mac OS X 下?也默认安装好了,嘿嘿 ^_^
Windows?啥也没安装 T_T。WTF ?!
通过二进制包安装
从www.python.org去下载一个……双击……一般请安装在C盘。如C:\Python25。
通过编译安装
我没这么装过……因为需要事先安装Visual C++之类的编译器,较为麻烦
ORZ……
开始学习一门新的语言,首要就是掌握如何用它来打印一行‚Hello, World‛。
Simon Cozens说:‚它是编程之神的传统咒语,可以帮助你更好的学习语言。‛
#!/usr/bin/env python# Filename: helloworld.py# Date: # Author: # Usage: chmod +x helloworld.py# ./helloworld.py
print ―Hello World‖
整数 - int
比如42就是一个整数
长整数 - long
‚长一点‛的整数。比如2222222222222222。
浮点数 - float
就是数学中的小数。比如4.2,4.2e-2(即0.042)。
复数 - complex
4+2j就表示复数。其中4是该复数的实部,2则是虚部。
使用单引号
‗Hello World‘
使用双引号
―Hello World‖
使用三引号(python特有)
‗‗‗Hello World ‘‘‘
转义符
\
自然字符串
r‘…..‘
Unicode字符串
u‘…..‘
字符串级连
‗hello‘ ‗world‘
在Python中常量就是值本身
比如1,‚1‛,1.1,‚1.1‛等等…
用什么存储常量?变量
变量的‚名字‛——标识符:
◦ 标识符的第一个字符必须是字母表中的字母(大写或小写)或者一个下划线‘ _’。
◦ 标识符名称的其他部分可以由字母(大写或小写)、下划线‘ _ ‘或数字(0-9)组成。
◦ 标识符名称是对大小写敏感的。例如,mysop和mySop不是同一个标识符。注意前者中的小s
和后者中的大S。
◦ 有效标识符名称的例子:
i、mySop、__name和a1b2_c3。
◦ 无效标识符名称的例子:
2things、this is spaced out和my-name。
_、__42、_42_、__42__、42__和42_,那个是正确的标识符?哪个是错误的标识符?
#!/usr/bin/env python# Filename: var_test.py
i = 42print ii = 42 + 1print is = ‗Hello World‘print ss = ‗‗‗this is a long long long longlong long long line‘‘‘
Lesson 2By Will Zhou
算术运算◦ + 加
◦ - 减
◦ * 乘
◦ / 除
◦ ** 幂
◦ // 取整除
◦ % 取模
>>> 1 + 1
2
>>> -2 – 3
-5
>>> 2 * 3
6
>>> 2 ** 3
8
>>> 8.0 / 3.0
2.6666666666666665
>>> 8.0 // 3.0
2.0
>>> 8.0 % 3.0
2.0
位运算◦ << 左移
5 << 1 == 10 <- 0101 << 1 == 1010 ( 二进制 )
◦ >> 右移
5 >> 1 == ?
◦ & 按位与
5 & 2 == 0 <- 0101 & 0010 == 0000 ( 二进制 )
◦ | 按位或
5 | 2 == 7 <- ?
◦ ^ 按位异或
5 ^ 2
◦ ~ 按位反
~X => -(X+1)
逻辑运算◦ < 小于 1<2 -> True
◦ > 大于 1>2 -> False
◦ <= 小于等于◦ >= 大于等于◦ == 等于 1+1 == 2 -> True
◦ != 不等于 1+1 != 3 -> True
◦ not 布尔非 not 1<2 -> False
◦ and 布尔与 2>1 and 3>2 -> True
◦ or 布尔或 2<1 or 3>2 -> True
运算符 描述
lambda Lambda表达式
or 或
and 与
not 非
in,not in 成员测试
is,is not 同一性测试
<,<=,>,>=,!=,== 比较
|,^,& 三个位运算,优先级分别是|低,^高,&最高
<<,>> 移位
+,- 加法、减法
*,/,% 乘法、除法、取模
+X,-X 正负号
~X 按位反
** 指数
(EXPRESSION, … ) 绑定或元组
运算符优先级表
从低到高(部分)
运算符优先级
运算符优先级表决定了哪个运算符在别的运算符之前计算
可以使用圆括号改变它们的计算顺序
#!/usr/bin/env python# Filename: simple_gray.py# Author: Will Zhou# Date: 2010-07-29 14:09:01
r = 0.3g = 0.8b = 0.6gray = 0.3*r + 0.6*g + 0.1*bprint grayr = g = b = gray
Nuke 演示
预览效果
if - elif - else 条件语句
#!/usr/bin/env python# coding=utf8# Filename: hfs_selector.py
import sys
if len(sys.argv) == 2: # 判断是否有2个参数(包括默认参数)ver = sys.argv[1] # 将命令行获取的参数赋给变量verif ver == ―10.0.595:‖ # 判断ver的值是否为字符串‖10.0.595‖
print ―cd /opt/hfs10.0.595‖print ―source houdini_setup‖print ―cd –‖
elif ver == ―11.0.446‖: # 如果不是,则继续判断print ―cd /opt/hfs11.0.446‖print ―source houdini_setup‖print ―cd –‖
else: # 否则,就干嘛……print ―echo Sorry, there is no such version houdini‖
while 循环
#!/usr/bin/env python# coding=utf8# Filename: image_check.py# Description: This code should be run in Nuke.
import osimport thread
def check():
# 如果图片不存在则继续循环while not os.path.exists(‗d:/test.tga‘):
pass # pass在程序不具体做什么的时候很好用# 循环退出的时候,将立刻执行下面的语句nuke.message(‗The image is ready!‘)
thread.start_new_thread(check, ())
while 循环
Nuke 演示
while 循环
Nuke 演示结果
for 循环
#!/usr/bin/env python# coding=utf8# Filename: for.py# Description: This code should be run in Houdini.
import hou
grid1 = hou.node(‗/obj/geo1/grid1‘) # 获取创建好的grid对象points = grid1.geometry().points() # 返回一个点序列for point in points: # 用 for 循环遍历序列中的各个点
print point.position() # 打印点的坐标
for 循环
Houdini 演示
break 和 continue 语句
break语句
是用来终止循环语句的,即哪怕循环条件没有称为False或序列还没有被完全递归,也停止执行循环语句。
continue语句
被用来告诉Python跳过当前循环块中的剩余语句,然后继续进行下一轮循环。
break 和 continue 语句
#!/usr/bin/env python# Filename: break.py
i = 1
while i < 10:print iif i > 5:
i = i + 1break
else:i = i + 1
print ‗break‘
#!/usr/bin/env python# Filename: continue.py
i = 1
while i < 10:print iif i > 5:
i = i + 1continue
else:i = i + 1
print ‗continue‘
1. 将 if 判断语句的代码例子,仔细的输入编辑器(如vim)中,保存名为 hfs_selector.py 的源代码文件,然后在终端中调用python命令执行该代码。将代码执行后的输出结果,在Linux终端执行一遍,然后思考一下整个过程。
2. 分别用while和for循环编写一个程序,程序的作用是打印出以下内容:
wof00101wof00102wof00103wof00104wof00105
#--------- while -----------#
i=1while i<10:
print ii = i +1
# ---------- for ----------- #
for i in range(1, 10):print i
第2题参考程序
如何利用循环嵌套,使程序做更多的事
#!/usr/bin/env python# coding=utf8# Filename: shot_codes.py# Author: Will Zhou# Description: print the shot codes.#
for i in range(1,4):for j in range(1, 6):
print ‗wof%03d%02d‘ % ( i, j)
wof00101wof00102wof00103wof00104wof00105
…wof00201wof00202
…wof00301wof00302
…wof00305
Lesson 3By Will Zhou
如何定义一个函数
#!/usr/bin/env python# coding=utf8# Filename: print_hello.py#
# 函数用def关键字定义,def后面是函数名,# 圆括号内则是函数的参数,# 冒号后的缩进内容是函数体。
def printHelloWorld(): # 函数名为printHelloWorld,无参数print ‗Hello World!‘ # 函数体
printHelloWorld()
带参数的函数
#!/usr/bin/env python# coding=utf8# Filename: name_fix.py#
def nameFix(filename): # filename是函数nameFixing的参数return filename.lower() # filename必须是字符串
# 字符串自带有lower、upper等函数
# 注意,这里的filename与函数内的filename是不一样的filename = ‗WOF00101_Efx_TeST_V001‘print ‗BEFORE:‘, filename
filename = nameFix(filename)print ‗AFTER:‘, filename
带默认值的参数
#!/usr/bin/env python# coding=utf8# Filename: version_change.py
def versionChange(filename, ver=‗001‘): # ver是带有默认值的参数‗‘‘ This function is used to change file versions‘‘‘ # 这是DocStrings
# help()函数会读取这个oldver = filename[-3:]filename = filename.replace(oldver, ver)return filename
filename = ‗wof00101_efx_test_v002‘print ‗BEFORE:‘, filename
filename = versionChange(filename)print ‗DEFAULT:‘, filename
filename = versionChange(filename, ver=‗009‘)print ‗NEW:‘, filename
递归函数
#!/usr/bin/env python# coding=utf8# Filename: remkdir.py# Author: Will Zhou# Description: 创建目录的时候,同时创建其父目录,即层层创建
def remkdir(folder):import os
if os.path.exists(folder): return # 如果存在,则用return跳出parent = os.path.dirname(folder)remkdir(parent) # 函数递归,跳出递归之后,将执行下面的语句if not os.path.exists(folder):
os.mkdir(folder)
应用举例
#!/usr/bin/env python# coding=utf8# Filename: doublesave.py# Description: 保存hip文件的同时,备份文件至指定目录# 本代码请保存至$HOME/houdini10.0/scripts/python/doublesave.py
def doublesave(backup=r"/home/will/backup/"):import osimport hou
hip_path = hou.getenv('HIP')
backup_path = ‗/‘.join([backup, hip_path])remkdir(backup_path) # 在backup变量指定的目录里,递归创建原hip文件的路径
filename = os.path.basename(hou.hipFile.name())back_file = ‗/‘.join([backup_path, filename])hou.hipFile.save(back_file)hou.ui.displayMessage(‗Backup to %s‘ % back_file)
origFile = os.path.join(hip_path, filename)hou.hipFile.save(origFile)
应用举例
from .. import .. 语句
# import 和 from…import…的区别# 请看下面程序
import osos.mkdir(―new_dir‖)
from os import mkdirmkdir(―new_dir‖)
# 一般来说,应该尽量用 import,因为 from…import…会涉及到命# 名污染(命名冲突)等问题。
模块的 __name__
#!/usr/bin/env python# Filename: print_hello.py# 说明:# 1. 每个模块都有 __name__# 2. __name__ == ‗__main__‘ 的作用是防止模块被import# 的时候执行某些代码# 3. 用python命令直接执行本程序的时候,# __name__ == ‗__main__‘ 下的子语句才会被执行#
def printHello():print ‗Hello World‘
if __name__ == ‗__main__‘:printHello()
如何调用自己的模块
#!/usr/bin/env python# Filename: main.py
from print_hello import printHello
if __name__ == ‗__main__‘:printHello()
用dir函数查看模块
# 比如自己创建的模块 print_hello
import print_hello
dir(print_hello)
# 也可以查看标准库及任何第三方的模块
import os
dir(os)
list - 列表
#!/usr/bin/env python# Filename: list.py#
projects = [‗WOF‘, ‗CRD‘, ‗SIX‘, ‗TCM‘, ‗BWE‘ ]
counts = len(projects)
print ―There are %d projects we‘re working in progress‖ % counts
print projects[0]print projects[-1]print projects[2:4] # 4为开区间,真正输出的是第2和第3这两个元素
projects.append(‗ABC‘)print projects
list是处理一组有序元素的数据结构。
tuple – 元组
元组和列表十分类似,只不过元组和字符串一样是不可变的,即你不能修改元组。
#!/usr/bin/env python# Filename: tuple.py#
projects = (‗WOF‘, ‗CRD‘, ‗SIX‘, ‗TCM‘, ‗BWE‘ )
counts = len(projects)
print ―There are %d projects we‘re working in progress‖ % counts
print projects[0]print projects[2:2] # 思考下这个输出哪个元素,然后再验证是否正确
projects.append(‗ABC‘) # 错误
dict – 字典
字典类似于你通过联系人名字查找地址和联系人详细情况的地址簿,即,我们把键(名字)和值(详细情况)联系在一起。
注意,键必须是唯一的。 #!/usr/bin/env python# Filename: dict.py
tasks = {‗Alex‘:‘EFX‘,‗Mark‘:‘CMP‘,‗Boris‘:‘RnD‘,}
print tasks.get(‗Boris‘)print tasks[‗Boris‘]
tasks.keys()tasks.values()tasks.items()
引用
#!/usr/bin/env python# coding=utf8# Filename: reference.py
shoplist = ['apple', 'mango', 'carrot', 'banana']mylist = shoplist # mylist是另外一个指向同shoplist所指的对象的名字del shoplist[0]print ‗shoplist is‘, shoplist # 两者输出一致print ‗mylist is‘, mylist # mylist这时就是shoplist的一个引用
mylist = shoplist[:] # 拷贝整个shoplist的切片del mylist[0] # 删除第一个元素print ‗shoplist is‘, shoplist # 两者已经各有所指print ‗mylist is‘, mylist # mylist不是shotlist的引用
字符串高级操作
startswith / endswith
upper / lower
find / index
replace
split
strip
join
isdigit
isalpha