Come verificare se la proprietà del nodo non è None durante l'iterazione dei materiali?
Sto riscontrando un errore senza attributi durante l'iterazione di nodi e gruppi di nodi in alcuni file blend.
Errore: AttributeError: l'oggetto 'NoneType' non ha l'attributo 'nome'
Come posso verificare se gli oggetti non hanno proprietà 'name' e saltarli?
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':
Risposte
Un attributo può essereNone
L'errore NoneType has no attribute
è un errore comune riscontrato negli script di Blender. Ad esempio può essere il caso checontext.object is None
All'OP consiglierei di modificare il titolo della domanda per riflettere maggiormente questo messaggio di errore.
Error: AttributeError: 'NoneType' object has no attribute 'name'
lanciato da node.node_tree.name == 'NodeGroupName'
sta informando node.node_tree
ha il valore None
. Può verificare che sia così, ad es
if node.node_tree is None:
al contrario di
if hasattr(node, "node_tree"):
Entrambi saranno veri quando lo è l'albero dei nodiNone
In realtà è strano che il codice in questione generi questo errore, poiché non sono (ancora) a conoscenza di come aggiungere un nodo di gruppo e non avere node_tree collegato. Ipotizzare che questo sia il risultato dell'eliminazione di un gruppo di nodi da bpy.data.node_groups
quello che era un nodo di un albero di nodi materiali..
quindi l'ultima riga del copione della domanda potrebbe essere
if (node.type in ["GROUP"]
and node.node_tree
and node.node_tree.name == 'NodeGroupName'
):
poiché il concatenamento e cessa al primoFalse
Usandogetattr
Dal momento che praticamente tratteremmo lo stesso usando l'attributo get con il terzo argomento predefinito
node_tree = getattr(node, "node_tree", None)
sarà None
in entrambi i casi. IMO questo "trionfa" utilizzando sia l'albero dei nodi has che il test degli attributi del nome. None
non ha nulla, se sappiamo che non c'è nessun ulteriore test per gli attributi sembrerebbe superfluo Può anche garantire che se un nodo albero non None
lo è avrà un nome .bpy.types.ShaderNodeTree.name
Sceneggiatura di prova
Usando quanto sopra con il "doppio test" per un nodo di 'GROUP'
tipo verifica che abbia un albero di nodi non nessuno.
Crea un dizionario, con chiavi corrispondenti al nome del gruppo di nodi contenente un elenco di nome materiale, tupples nome nodo.
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)
Produzione.
File con 1 gruppo di nodi "Test_Material", 2 materiali "TestMat" e "TestMat.001".
Il gruppo di nodi viene utilizzato in entrambi i materiali con il nome "Gruppo" in entrambi.
['Test_Material']
defaultdict(<class 'list'>, {'Test_Material': [('TestMat', 'Group'), ('TestMat.001', 'Group')]})
Appunti:
Attenzione all'equivalenza True
o False
nei test. Per impostazione predefinita, Python equipara la maggior parte dei tipi a True o false. Alcuni esempi di false sono None
, il numero intero 0
e una lista vuota[]
Metodi come hasattr
return o True
oFalse
if hasattr(foo, "bar") == True:
se foo.bar
esiste questo si legge in qualche modo simile a
if True == True:
invece usa semplicemente
if hasattr(foo, "bar"):
Cambiare leggermente sopra per restituire boolean false invece di none quando il nodo non ha l'attributo node_tree, if nt:
sarà falso in entrambi i casi, ma possiamo discernere tra i due.
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")
Basato sul commento di 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':