Python Argument Handling and Houdini Scripting Techniques
Variable-Length Function Parameters
Python supports flexible argument passing using special syntax:
def process_data(*params, **config):
print(params)
print(list(config.items()))
process_data(1, 2, name="Zhang", country="China")
Output:
(1, 2)
[('name', 'Zhang'), ('country', 'China')]
The single asterisk (*params) collects positional arguments into a tuple. The double asterisk (**config) collects keyword arguments into a dictionary. Positional arguments must precede keyword arguments in function definitions.
File System Operations
import subprocess
path = '/Users/myuser/mydata/'
result = subprocess.run(
['ls', '-t', path + '*.bgeo.sc'],
capture_output=True,
text=True
)
files = result.stdout.splitlines()
print(files[-2])
Node Hierarchy Traversal
def getAllDescendants(node):
descendants = []
for child in node.children():
descendants.append(child)
descendants.extend(getAllDescendants(child))
return descendants
Houdini Network Editor Operations
Node Creation at Cursor Position
network = hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor)
cursor_pos = network.selectPosition()
new_node = network.pwd().createNode("box")
new_node.setPosition(cursor_pos)
Animation Keyframing System
def keyAllParameters():
parms = hou.pwd().parms()
current_frame = hou.intFrame()
for p in parms:
if p.parmTemplate().type() == hou.parmTemplateType.Float:
p.setKeyframe({
'frame': current_frame,
'value': p.eval()
})
def resetAllParameters():
parms = hou.pwd().parms()
for p in parms:
if p.parmTemplate().type() == hou.parmTemplateType.Float:
p.deleteAllKeyframes()
p.set(0.0)
Node Export/Import System
# Export selected nodes
selected = hou.selectedNodes()
with open("/tmp/node_paths.txt", "w") as f:
for node in selected:
f.write(node.path() + "\n")
# Import and merge nodes
with open("/tmp/node_paths.txt", "r") as f:
paths = [line.strip() for line in f if line.strip()]
editor = hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor)
position = editor.selectPosition()
parent = editor.pwd()
merge_node = parent.createNode("merge", "combined_geometry")
for idx, path in enumerate(paths):
name = path.split("/")[-1]
obj_merge = parent.createNode("object_merge", f"import_{name}")
obj_merge.parm("objpath1").set(path)
obj_merge.parm("xformtype").set(1)
obj_merge.setPosition((position[0] + idx * 2, position[1]))
merge_node.setInput(idx, obj_merge)
merge_node.moveToGoodPosition()
merge_node.setDisplayFlag(True)
merge_node.setRenderFlag(True)