Comment vérifier si la propriété du nœud n'est pas None lors de l'itération des matériaux ?
Je rencontre une erreur d'absence d'attribut lors de l'itération des nœuds et des groupes de nœuds dans certains fichiers blend.
Erreur : AttributeError : l'objet 'NoneType' n'a pas d'attribut 'name'
Comment vérifier si les objets n'ont pas de propriété 'name' et l'ignorer?
for mat in bpy.data.materials:
if mat.use_nodes == True:
for node in mat.node_tree.nodes:
#check if no has attribute name
if node.type in ["GROUP"] and node.node_tree.name == 'NodeGroupName':
Réponses
Un attribut peut êtreNone
L'erreur NoneType has no attribute
est une erreur courante rencontrée dans les scripts Blender. Par exemple, il peut arriver quecontext.object is None
Pour l'OP, je recommanderais de modifier le titre de la question pour refléter davantage ce message d'erreur.
Error: AttributeError: 'NoneType' object has no attribute 'name'
jeté par node.node_tree.name == 'NodeGroupName'
est informant node.node_tree
a la valeur None
. Peut tester si c'est le cas, c'est-à- dire
if node.node_tree is None:
par opposition à
if hasattr(node, "node_tree"):
Les deux seront vrais lorsque l'arborescence de nœuds estNone
C'est en fait un cas étrange que le code en question génère cette erreur, car je ne sais pas (encore) comment ajouter un nœud de groupe et n'avoir aucun node_tree lié. Supposons que cela soit le résultat de la suppression d'un groupe de nœuds bpy.data.node_groups
qui était un nœud d'une arborescence de nœuds de matériau.
par conséquent, la dernière ligne du script de question pourrait être
if (node.type in ["GROUP"]
and node.node_tree
and node.node_tree.name == 'NodeGroupName'
):
puisque l'enchaînement des ands cesse le premierFalse
Utilisantgetattr
Puisque nous traiterions à peu près la même chose en utilisant l'attribut get avec le troisième argument default
node_tree = getattr(node, "node_tree", None)
le sera None
dans les deux cas. IMO cela "l'emporte" en utilisant à la fois l'arborescence de nœuds puis le test d'attribut de nom. None
n'a rien, si nous savons qu'il n'y en a pas, tester davantage les attributs semblerait superflu . Peut également garantir que si un arbre de nœuds ne l'est pas None
, il aura un nom .bpy.types.ShaderNodeTree.name
Scénario de test
En utilisant ce qui précède avec le "double test" pour un nœud de 'GROUP'
type check, il a une arborescence de nœuds non nulle.
Créez un dictionnaire, avec des clés correspondant au nom du groupe de nœuds contenant une liste de noms de matériaux et de noms de nœuds.
import bpy
from bpy import data
from collections import defaultdict
# all the group nodes in blendfile
print(data.node_groups.keys())
group_nodes = defaultdict(list)
# create a look up dictionary
for m in data.materials:
if m.use_nodes:
for n in m.node_tree.nodes:
nt = getattr(n, "node_tree", None)
if nt and n.type == 'GROUP':
group_nodes[nt.name].append((m.name, n.name))
print(group_nodes)
Production.
Fichier avec 1 groupe de nœuds "Test_Material", 2 matériaux "TestMat" et "TestMat.001".
Le groupe de nœuds est utilisé dans les deux matériaux avec le nom "Groupe" dans les deux.
['Test_Material']
defaultdict(<class 'list'>, {'Test_Material': [('TestMat', 'Group'), ('TestMat.001', 'Group')]})
Remarques:
Méfiez-vous des assimilation à True
ou False
dans les tests. Par défaut, Python assimile la plupart des types à True ou False. Quelques exemples de false sont None
, l'entier 0
et une liste vide[]
Des méthodes comme hasattr
return soit True
ouFalse
if hasattr(foo, "bar") == True:
s'il foo.bar
existe, cela ressemble un peu à
if True == True:
utilisez plutôt simplement
if hasattr(foo, "bar"):
Changer légèrement ci-dessus pour renvoyer boolean false au lieu de none lorsque le nœud n'a pas d'attribut node_tree, if nt:
sera faux dans les deux cas, mais nous pouvons discerner entre les deux.
nt = getattr(n, "node_tree", False)
if nt and n.type == 'GROUP':
group_nodes[nt.name].append((m.name, n.name))
if nt is None:
print(f"{m.name}:{n.name} node_tree is None")
Basé sur le commentaire de Ron Jensens :
for mat in bpy.data.materials:
if mat.use_nodes == True:
for node in mat.node_tree.nodes:
if hasattr(node, 'node_tree') == True:
if hasattr(node.node_tree, 'name') == True:
if node.type in ["GROUP"] and node.node_tree.name == 'NodeGroupName':