I’m trying to use Python more in my daily workflow. Even when I work with Dynamo nodes, I usually look for the Python equivalent. However, sometimes I struggle to understand the correct inputs. For example, yesterday I was using:
Import Autodesk.DesignScript.Geometry as DG
DG.Surface.PerimeterCurves(element)
element.PerimeterCurves()
It looks like there are two different approaches or methods, which can be confusing.
Is there any website or resource where I can learn the Python equivalents for Dynamo nodes?
What you’re pondering is actually a feature of Python, not so much an inconsistency in Dynamo.
The first way Python allows us to call a method is by first declaring the class (Surface) the method is in, followed by a dot (.) followed by a method (PerimeterCurves) followed by the sequence of inputs in parentheses ((yourSurface)).
The second way is by letting Python handle the class bit for you - it already knows that yourSurface is an instance of the surface class and so you can skip that step. This is done by calling the instance of a member in the class you want to use (yourSurface) followed by a dot (.) followed by the method (PerimeterCurves) folllwed by parentheses with any other inputs (()). In this case the inputs list is empty as yourSurface was provided as the instance to call.
As far as which you would want to call when, different Python engines handle the two options differently in some very unique circumstances, so it’s good to know both. However try to standardize on one or the other in any given code base at it will keep you from going insane. Personally I prefer the instance based method as it reduces the amount of typing, but in some cases I’ll go full class to maintain clarity for other users.
One last note: try to use variable names which align to the object’s type. You may have noticed I used yourSurface in my sample instead of ‘element`. This was because Element is a class which can lead to confusion in 5 years or five weeks or five days from now when your future self see you calling for PerimeterCurves from the Dynamo API using a Revit Element as the instance as there is no Element.PerimeterCurves in the Revit API. Sure it’s a few more characters to type in your variable name, but it keeps things clear in the future and that will save time.
Really appreciate the detailed explanation, Jacob — this clears up a lot of confusion for me. Seeing the difference between class-based and instance-based calls explained this way makes it much easier to understand why both exist. I’ve started building my own reference file to test which methods work best in practice, so your point about staying consistent in one style is something I’ll definitely keep in mind.
Also completely agree about naming — I’ve already experienced how confusing generic names can get when mixing Dynamo geometry and Revit API objects. Thanks again for taking the time to share such a clear breakdown!
with Pythonnet or IronPython It is possible to call CLR managed methods “unbound” (passing the instance as the first argument) just as with Python methods. This is most often used to explicitly call methods of a base class.
As @jacob.small said, it is preferable not to use unbound methods if your method is an instance method (if only for the sake of rereading your code in a few months or years).
It can sometimes be useful to use unbound methods (e.g., COM objects).
Here is a utility function to find out the methods (including whether it is a static method) of a type (Net).
# Load the Python Standard and DesignScript Libraries
import sys
import clr
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
from System.Reflection import BindingFlags
import re
flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly
def get_infos_NetType(obj):
markdown_lines = []
ncls = obj.GetType()
methods = ncls.GetMethods(flags)
if methods:
markdown_lines.append("### Methods")
for method in sorted(methods, key=lambda x: x.Name):
if not method.Name.startswith(("get_","set_", "op_")):
b_method_name = method.ToString()
method_name_simple = method.Name
# paramters
paramters = ", ".join([
pInfo.ParameterType.ToString() + "=" + str(pInfo.RawDefaultValue )\
if pInfo.HasDefaultValue and not System.String.IsNullOrEmpty(str(pInfo.RawDefaultValue ))\
else pInfo.ParameterType.ToString()\
for pInfo in method.GetParameters()
])
return_value = "Void"
is_static = "static " if method.IsStatic else ""
check_patern = re.match(r"^(.+?)\s(.*\(.*\))$", b_method_name)
if check_patern is not None:
return_value = check_patern.group(1)
method_name = check_patern.group(2)
markdown_lines.append(f"- `{is_static}{method_name_simple}({paramters})` → `{return_value}`")
markdown_lines.append("")
return markdown_lines
pt = Point.ByCoordinates(0,0,0)
info = get_infos_NetType(pt)
OUT =info