Python get and set parameter values

Which is the more efficient way to get and set multiple parameter values (lists) using only Python?

Jeremy’s (Tammik) comments:

There is no need to loop over all parameters.

You can access the parameter on the element directly without looping.

There are lots of examples of more efficient approaches in The Building Coder discussions.

You also simply search for the string “.Set(” in The Building Coder samples:

Cheers,

Hello,

Actually We try as indepent as possible from all packages! We work just with buildin Nodes.
We rebuild via Python our nodes, here is (german) tutorial:

how we do our stuff. I can`t directly answer your question…

KR

Andreas

1 Like

Vielen Danke @Draxl_Andreas!

Ich spreche ein wenig Deutsch, also ist es sehr nützlich!

I am also trying to only write in Python, also to be able to easily adapt the codes into C#.

Thanks!

1 Like

What type of parameters are you trying to set? Are they built-in parameters, or project / shared parameters?

If you know the name of them the easiest way is

element.LookupParameter("paramName").Set(Value)

A couple things to watch out here is that sometimes there may be more than one parameter with the same name, make sure you are getting the Instance or Type for the correct parameter, and that the Value is the correct type (Integer, string, double, ElmentId).

5 Likes

Hi @SeanP

I am after getting either builtIn, project, or shared parameters of all the elements of a category (for example) and set the values into a Shared Parameter.

I will know normally the parameter name. The type will be normally a text parameter, but I would rather be able to work with any parameter type, so that the code has this flexibility…

If you could provide an example would be great!

Thanks in advance

If you want a piece of code that will retrieve a parameter value no matter the data type, you’re going to have to check the storage type of each parameter, and then use that to decide which .As…() method you use.

Thanks @stewart.skyler

That is useful. Could you please provide me with an example?

st = your_parameter.StorageType
if str(st) == 'Double':
    value = your_parameter.AsDouble()
elif str(st) == 'String':
    value = your_parameter.AsString()
elif ...

with one line for each data type.

1 Like

Thanks, @stewart.skyler, that’s useful.

Considering I have my list of values (get parameter values from all the elements of a category (i.e: casework)), Would you be able to help me with Setting the parameter values into a Shared Parameter (i.e: Text parameter type, string values).

Thanks in advance.

Oh, sure, setting parameter values is pretty straight forward - Since we’re using Python, you can just set the parameter equal to whatever value you need. e.g.
your_parameter = your_value
(Actually you might be able to do that in C# as well, I’m not sure.)

You can also do
your_parameter.Set(your_value)
as is listed in the Parameter Methods on the API site.

I very highly recommend getting familiar with navigating the API site - https://www.revitapidocs.com/

Hi @stewart.skyler et al (@SeanP)

Thanks for your quick answer!

Let me be more precise, below is my python code, harvesting casework elements, casework element levels values, and the parameter where the level values will be added. Somehow, it is not setting the level list, but only one of the values from my input (level’s values) list:

Any help will be appreciated:

import clr

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

# Used to Ensure that object is in a list...
def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

elems = tolist(UnwrapElement(IN[0]))
Names = tolist(IN[1])
Vals = tolist(IN[2])

outList = []

dut = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits

if len(elems) == len(Vals):
	TransactionManager.Instance.EnsureInTransaction(doc)
	for e in elems:
		for n,v in zip(Names,Vals):
			try:
				p = e.LookupParameter(n)
				if p.Definition.ParameterType == ParameterType.Length:
					v = UnitUtils.ConvertToInternalUnits(v,dut)
				p.Set(v)
				outList.append(e)
			except Exception, ex:
				outList.append(ex.message)

	TransactionManager.Instance.TransactionTaskDone()

	OUT = outList, Vals
else:
	OUT = "Number of P.Values doesnt match Number of Elements"

image

Is the CRR_LEVEL parameter a string? Is the CRR_LEVEL a type or instance parameter?

One thing I may suggest to avoid any list level miss match is to do the GET LEVELS code inside the single SetParameter node unless you need it somewhere else.

And even more so, i can appreciate learning Python, but what you are showing could and should most likely be done with OOTB nodes for simplicity.

Hi @SeanP,

Thanks for your answer,

0 Correct, CRR_LEVEL parameter is a string. CRR_LEVEL is an instance shared parameter.

1 I am happy to do that

2 I appreciate that would be more simple using existing nodes, however, my query is Python-related only…

Hi @SeanP

1 Regarding your suggestion, I believe it would be something like that. However, still having the same issue

Any help will be appreciated, thanks!

image

import clr

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

# Used to Ensure that object is in a list...
def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

elems = tolist(UnwrapElement(IN[0]))
Names = tolist(IN[1])
outList = []
###############################
#Level Values
Vals = []
for f in elems:
	if hasattr(f, 'LevelId'):
		lvl = f.Document.GetElement(f.LevelId)
	elif hasattr(f, 'Level'):
		lvl = f.Level
	elif hasattr(f, 'GenLevel'):
		lvl = f.GenLevel
	else:
		try:
			p = f.get_Parameter(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM)
			lvl = f.Document.GetElement(p.AsElementId())
		except:
			lvl = None
	try:
		Vals.append(lvl.Name)
	except:
		Vals.append(None)

##############################

dut = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits

if len(elems) == len(Vals):
	TransactionManager.Instance.EnsureInTransaction(doc)
	for e in elems:
		for n,v in zip(Names,Vals):
			p = e.LookupParameter(n)
			p.Set(v)
			outList.append(e)
			
	TransactionManager.Instance.TransactionTaskDone()

	OUT = outList, Vals
else:
	OUT = "Number of P.Values doesnt match Number of Elements"

What I was trying to get at is combing the level information with the parameter setting as well. So you would look the elements and get the level value Name in line with the other information. That way you are trying to pick an item from one list to insert in the other.

1 Like

Looks like it has to do with the structure of your lists. If you set your code to output just the data, so to speak, you can a bit more what it’s doing.


If you’ll notice in my output list, the first element (in my case a wall) is listed multiple times. So it’s being overwritten each loop.

I’m not exactly sure I’m understanding your end goal right, but it looks to me like you could zip it all into one list:

import clr

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

# Used to Ensure that object is in a list...
def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

elems = tolist(UnwrapElement(IN[0]))
Names = tolist(IN[1])
Vals = tolist(IN[2])

outList = []

dut = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits

if len(elems) == len(Vals):
	TransactionManager.Instance.EnsureInTransaction(doc)
	for e,n,v in zip(elems, Names,Vals):
		try:
			p = e.LookupParameter(n)
			if p.Definition.ParameterType == ParameterType.Length:
				v = UnitUtils.ConvertToInternalUnits(v,dut)
			p.Set(v)
			outList.append(e)
		except Exception, ex:
			outList.append(ex.message)

	TransactionManager.Instance.TransactionTaskDone()

	OUT = outList, Vals
else:
	OUT = "Number of P.Values doesnt match Number of Elements"

1 Like

Hi @stewart.skyler

I just want to set the values from my input list Vals = tolist(IN[2]) [Casework Levels] into a Shared Parameter CRR_LEVEL

Only that…

Hi @SeanP

Thanks for the suggestion, it makes sense. Probably the error is related to that

If you would be able to assist in implementing your suggestion in my code would be much appreciated…

Thanks

In that case I believe my script should work, however, if your parameter name is consistent you don’t need to turn it into a list.

import clr

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

# Used to Ensure that object is in a list...
def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

elems = tolist(UnwrapElement(IN[0]))
Name = IN[1]
Vals = tolist(IN[2])

outList = []

dut = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits

if len(elems) == len(Vals):
	TransactionManager.Instance.EnsureInTransaction(doc)
	for e,v in zip(elems, Vals):
		try:
			p = e.LookupParameter(Name)
			if p.Definition.ParameterType == ParameterType.Length:
				v = UnitUtils.ConvertToInternalUnits(v,dut)
			p.Set(v)
			outList.append(e)
		except Exception, ex:
			outList.append(ex.message)

	TransactionManager.Instance.TransactionTaskDone()

	OUT = outList, Vals
else:
	OUT = "Number of P.Values doesnt match Number of Elements"

Just to make it a bit easier to read, if we remove all the error checking this is all we’re really doing:

[e.LookupParamter("CRR_LEVEL").Set(v) for (e,v) in zip(elems, Vals)]
4 Likes

Brilliant, thanks @stewart.skyler

Appreciate your help.

Cheers,

1 Like