= Python parameter expressions = == Setting the Expression Language == Parameter expressions may be written using either the Hscript expression language or the Python expression language. You can mix and match the languages, so some parameters in a node may use Hscript expressions while other parameters in the same node use Python expressions. In HOM terminology, a parameter can be in one of two states: animated or not animated. An animated parameter has a set of keyframes. Each keyframe contains a time and an expression (as well as other information discussed later). A keyframe is active from its time up to the next keyframe, or until the end of the time range if there is no next keyframe. When Houdini evaluates a parameter at a particular time, it looks up the keyframe corresponding to that time and evaluates the expression. So, when someone says a parameter has an expression, he or she typically means that it has a single keyframe at time=0, and they're referring that that keyframe's expression. The convenience functions [Hom:hou.Parm.expression] and [Hom:hou.Parm.setExpression] provide easy access to that expression. There are two ways to control a parameter's language, depending on whether or not the parameter is already animated. If it is not animated and you write an expression in it, Houdini uses the node's expression language. The parameter dialog displays the node's language as either an H (for Hscript expressions) or the Python logo (for Python expressions). Changing the node's language does not affect parameters that already have expressions; it simply determines the language for new expressions you write. If a parameter's language is different from the node's language, Houdini will highlight that parameter in pink to make you aware of that difference. You can control the default expression language for newly created nodes with a preference in Houdini's main preference dialog. If the parameter is already animated, you can change its language by right-clicking on it and selecting "Expression -> Change Language to Python" or "Change Lanuage to Hscript Expressions". For most expressions, changing the language will generate an error because of syntactical and API differences between Hscript expressions and Python. However, certain functions, like [ch|Hom:hou.ch] and the animation functions ([cubic|Hom:hou.cubic], [bezier|Hom:hou.cubic], etc.) have been carefully designed to use the same syntax in both Hscript expressions and Python. For those expressions, you change change the language without generating errors or changing the output of those parameters. == Single and Multi Line Python Expressions == With Python parameter expressions, there is one simple rule you need to know: single lines are evaluated as standard expressions, and multiple lines are evaluated as function bodies. For example, `2+2` and `ch("ty") + 2` are valid Python expressions, but `x=3` and `x=3; x` are not. However, if you press Alt+e to bring up the multi-line editor, you can enter the following Python function body: {{{ #!python if ch("ty") == 0: return 0 if ch("ty") < 0: return ch("tx") return ch("tz") }}} From a Python function body you can run arbitrary Python statements, giving you full access to Python's standard library. Beware that Houdini may evaluate the parameter more often than you expect. == Python Expression Namespaces == Python expressions run in a different namespace than the global namespace provided by the Python shell. This way, you don't have to worry about Python global variables created in the shell affecting the output of parameter expressions, and vice versa. Also, to reduce the length of your Python parameter expressions, Houdini implicitly runs `from hou import *` and from `hou.session import *` in the Python expression namespaces. This means you can drop the `hou.` prefix in your Python expressions, and you can call hou.session functions as though they were defined locally. For example, in a Python expression you can write `ch("ty")` instead of `hou.ch("ty")`. Similarly, Houdini imports the following functions from Python's math module: acos, asin, atan, atan2, ceil, cos, cosh, degrees, exp, fabs, floor, log, log10, pow, radians, sin, sinh, sqrt, tan, tanh Because the expression operates in a different namespace, Houdini's global Python namespace is not polluted by these imports. TIP: If you really want to access a global variable from a Python expression, you can run `import __main__` to get access to Houdini's global Python namespace. For example, if `foo` is a function defined in your pythonrc.py file, you can access `foo` from a Python expression via `__main__.foo`. == String Parameter Expressions == Note that when Houdini evaluates string parameters without expressions, it will do string expansion on the result. So, if the unanimated string parameter contains `image$F.pic`, Houdini will expand $F, regardless of whether or not the node's language is set to Hscript expressions. However, if you animate the string parameter, using the Hscript expression language, the expression needs to be `"image$F.pic"`, because `image$F.pic` is not a valid Hscript expression evaluating to a string. (To convince yourself of this, run `echo \`image$F.pic\`` and `echo \`"image$F.pic"\`` in a textport.) Houdini's UI goes through great pains to automatically convert between unexpanded strings and Hscript expressions for you, and the UI often tries to hide the actual expression. (To see the expression, you can inspect the [hou.Keyframe] with [hou.Parm.keyframes].) For Python string expressions, you also need to write a valid Python expression, such as `"image %d" % frame()`. Thankfully, Houdini will let you see and edit those expressions, and it does not second-guess your intentions and automatically modify those expressions for you. == Local Variables == You can access Hscript expression local variables from Python with [Hom:hou.lvar]. For example, you can write the Hscript expression `$TX` in Python as `lvar('TX')`. Note that [Hom:hou.lvar] cannot access hscript global variables; for evaluate them, use [Hom:hou.expandString]. Many local variables in Houdini correspond to a SOP or POP that iterates over a number of points or primitives, evaluating the nodes parameters for each iteration. Each time the parameters are evaluated, Houdini uses a different value for the local variable, corresponding to the current point or primitive. The hou module provides [Hom:hou.SopNode.curPoint], [Hom:hou.SopNode.curPrim], and [Hom:hou.PopNode.curPoint], giving you access to a [Hom:hou.Point] or [Hom:hou.Prim] object. So, for example, `lvar('Cr')` in a Point SOP could also be written as `curPoint().attribValue('C')[0]`. While this approach is more verbose and has additional overhead, it is more generic, giving you access to information in points and primitives that may not be available through local variables. == Interrupting Expression Evaluation == If you call Python code that takes a long to evaluate, or it goes into an infinite loop, you can press Escape to interrupt expression evaluation. NOTE: On Linux, if HOUDINI_ENABLE_LINUX_THREADED_UI is off, Python expression evaluation cannot be interrupted.