AttributeError: Name ?
if this article is not in your language, use the Google Translate widget (bottom of page for Mobile version)⬈
C’est une question qui revient souvent, comment obtenir le nom d'un Type ou d'une Pièce depuis Python ?
Pour certaines Propriétés, l'interpréteur Python ne semble pas aller chercher au-dessus dans l'arbre d'héritage.
Le problème vient du fait que la Propriété .NET n'est pas accessible dans les classes dérivées où seul le setter ou le getter a été implémenté.
À noter que seul le language Python semble être exposé à ce problème (IronPython ou CPython/PythonNet)
Aperçu des 2 cas les plus fréquents :
Voici quelques méthodes pour y parvenir, qui fonctionnent ou non suivant le moteur Python
Résumé comparatif de méthodes avec un temps d'exécution moyen pour 5000 éléments.
'e' étant l'élément (ElementType ou Pièce) dont l'on cherche le Nom
Méthodes
\
Moteur Python |
IronPython 2.7 |
CPython3 / PythonNet2.5 |
IronPython 3.x |
CPython3 / PythonNet3.x |
---|---|---|---|---|
Property : e.Name |
✘ | ✘ | ✔ | ✔ |
System.Reflection: clr.GetClrType(e.GetType()).GetMethod('get_Name').Invoke(...) |
✔ temps pour 5000 éléments : 0.022 s |
✔ temps pour 5000 éléments : 0.177 s |
||
System.Reflection.PropertyInfo BaseType.GetProperty('Name').GetValue(e) |
✔ temps pour 5000 éléments : 0.049 s |
✔ temps pour 5000 éléments : 0.289 s |
||
Unbound_class_instance Element.Name.GetValue(e) ou Element.Name.__get__(e) |
✔ temps pour 5000 éléments : 0.044 s |
✘ | ||
get_Method e.get_Name() |
✘ |
✔ temps pour 5000 éléments : 0.046 s |
||
ToDSType() wrapper conversion e.ToDSType(False).Name |
✔ temps pour 5000 éléments : 1.379 s |
✔ temps pour 5000 éléments : 1.141 s |
||
BuiltInParameter e.get_Parameter(BuiltInParameter.XX).AsString() |
✔ temps pour 5000 éléments : 0.028 s |
✔ temps pour 5000 éléments : 0.089 s |
import clr
import sys
import System
import timeit
# import Revit API
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
e=FilteredElementCollector(doc).OfClass(ViewFamilyType).FirstElement()
def Get_Name(obj, type = None, i = 0):
if isinstance(obj, Autodesk.Revit.DB.Element) and i < 10:
type = type if type is not None else obj.GetType()
if type.ToString() == 'Autodesk.Revit.DB.Element':
return type.GetProperty('Name').GetValue(obj)
else:
return Get_Name(obj, type.BaseType, i + 1)
class MyTestClass:
def __init__(self):
pass
def get_ByProperty(self):
"""Property -> e.Name"""
viewName = e.Name
def get_ByReflection(self):
"""Method -> clr.GetClrType(type).GetMethod('get_Name').Invoke(...)"""
viewName = clr.GetClrType(e.GetType()).GetMethod('get_Name').Invoke(e, None)
def get_ByReflectionBaseType(self):
"""Method -> e.GetType().BaseType.GetProperty('Name').GetValue(e)"""
viewName = Get_Name(e)
def get_ByUnbound_class_instance(self):
"""Method -> Element.Name.GetValue()"""
# OR
# DB.Element.Name.__get__(e)
viewName = Element.Name.GetValue(e)
def get_ByMethod(self):
"""Method -> get_Name()"""
viewName = e.get_Name()
def get_ByDSType(self):
"""Property -> e.ToDSType(False).Name"""
viewName = e.ToDSType(False).Name
def get_ByParameter(self):
"""Property -> e.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString()"""
viewName = e.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString()
# Example for Spatial Element
#spName = e.get_Parameter(BuiltInParameter.ROOM_NAME).AsString()
obj = MyTestClass()
methods_list = [getattr(obj, attribute) for attribute in dir(obj) if callable(getattr(obj, attribute)) and not attribute.startswith('__')]
result = []
for method in methods_list:
try:
t = timeit.Timer(lambda : method())
testTime = str(round(t.timeit(5000), 3)) + " s"
result.append("'{}'\nSUCCESS 5000 times at {}\nin {}\n{}".format(method.__doc__, testTime, sys.implementation.name, sys.version))
except Exception as ex:
result.append("'{}'\n FAILED in {}\n{}\nError : {}".format(method.__doc__, sys.implementation.name, sys.version, ex))
result.append('-' * 20)
OUT = result
Bon article.
RépondreSupprimerMême genre de problème pour aller chercher le nom des paramètres de projet ou paramètres partagés. <- sujet d'article potentiel?
Salut Jean-Marc,
Supprimerregarde cet article il pourra peut-être t’intéresser
https://voltadynabim.blogspot.com/2020/04/dynamopython-exemple-ui-visualisation.html
Tres bon article!
RépondreSupprimerMerci :)
SupprimerVery nice, Cyril. Cheers for the explanation :-)
RépondreSupprimer