Python 3 in Rhino

Python 3 in Rhino

Rhino 8 and newer, embed two Python runtimes side by side:

Python 3 is an addition, not a replacement. Your Python 2 scripts keep running on IronPython, and both runtimes are available in Rhino and in Grasshopper.

Scripts of either runtime are written in a refreshed Script Editor, and it is the editor that puts the rest of this page within reach: installing packages, and a real debugger with breakpoints, variables, and a call stack. That debugger also works inside Grasshopper components, which the old editor could not do.

What You Get With Python 3

Python 3 opens up the wider Python world:

  • Packages from PyPI such as numpy, declared in the script itself with #r: numpy
  • Separate package environments, for packages that clash with each other
  • Current Python language features, and the libraries that expect them
#r: numpy

import numpy as np
import rhinoscriptsyntax as rs

points = np.random.rand(10, 3) * 100

for point in points:
    rs.AddPoint(*point)

What Python 2 Still Does Better

IronPython runs on .NET with nothing in between, which shows in two places:

  • Pure RhinoCommon calls are faster
  • Real .NET multithreading is available

So the choice is per script rather than once and for all. Scripts that lean on packages want Python 3. Scripts that hammer RhinoCommon, or that need threads, can be better off staying on Python 2.

The Script Editor

Scripts of both runtimes are written in the Script Editor, opened with the ScriptEditor command. The same command runs scripts from macros, toolbar buttons, and aliases:

_-ScriptEditor _R "C:\path\to\script.py"

See ScriptEditor Command in Macros for the other command options, and Scripting: Python for writing and debugging scripts.

Note
The EditPythonScript command and its editor still exist, but are deprecated. New work belongs in ScriptEditor.

Python 3 in Grasshopper

Grasshopper has a Python 3 script component alongside the older GHPython component. ghpythonlib works the same under Python 3 as it does under Python 2:

import ghpythonlib.components as ghcomp

a = ghcomp.Circle(x, y)

Grasshopper 2 ships its own Python 3 and Python 2 script components. ghpythonlib is a Grasshopper 1 library and is not available there.

Details are in the component guides:

Publishing Scripts as Plugins

Scripts do not have to stay scripts. The Script Editor can gather them into a project and build that project into a Rhino or Grasshopper plugin, so your scripts become Rhino commands and Grasshopper components that others install like any other plugin.

Moving a Script to Python 3

Most of the work is ordinary Python 2 to Python 3 work: print is a function, / on two integers no longer truncates, range replaces xrange, and str replaces basestring. The Python documentation covers the language changes.

Three changes catch Rhino scripts in particular.

Enum members named None. None is a keyword in Python, so Python.NET exposes such members in upper case:

# python 2
value = Rhino.Geometry.Mesh.MeshType.None

# python 3
value = Rhino.Geometry.Mesh.MeshType.NONE

Methods returning collections. A .NET method returning an IEnumerable gives you an iterator in Python 3, not a list. Wrap it when you need indexing or a length:

items = list(some_method())

Subclassing .NET types. Python.NET expects the base constructor to be called, so a class deriving from a .NET type needs a super() call in its __init__. IronPython let you leave it out:

import Rhino

class MyConduit(Rhino.Display.DisplayConduit):
    def __init__(self):
        # required in python 3
        super().__init__()

        self.points = []

Without it, the object is not fully constructed and calls into it fail.