Como verificar se a propriedade do nó não é None durante a iteração por meio de materiais?
Estou encontrando um erro sem atributo ao iterar por meio de nós e grupos de nós em alguns arquivos de combinação.
Erro: AttributeError: objeto 'NoneType' não tem atributo 'name'
Como eu verificaria se os objetos não têm propriedade 'name' e a ignoraria?
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':
Respostas
Um atributo pode serNone
O erro NoneType has no attribute
é um erro comum visto no script do Blender. Por exemplo, pode ser o caso quecontext.object is None
Para o OP, recomendaria editar o título da pergunta para refletir mais essa mensagem de erro.
Error: AttributeError: 'NoneType' object has no attribute 'name'
lançado por node.node_tree.name == 'NodeGroupName'
está informando node.node_tree
tem o valor None
. Pode testar se esse é o caso, ou seja ,
if node.node_tree is None:
em oposição a
if hasattr(node, "node_tree"):
Ambos serão verdadeiros quando a árvore do nó forNone
Na verdade, é um caso estranho que o código em questão lançaria esse erro, pois não sei (ainda) como adicionar um nó de grupo e não tenho node_tree vinculado. Especule que este é o resultado da exclusão de um grupo de nós bpy.data.node_groups
que era um nó de uma árvore de nós de material.
portanto, a última linha do script de pergunta poderia ser
if (node.type in ["GROUP"]
and node.node_tree
and node.node_tree.name == 'NodeGroupName'
):
já que o encadeamento es cessa no primeiroFalse
Usandogetattr
Já que trataríamos praticamente o mesmo usando get attribute com o terceiro argumento default
node_tree = getattr(node, "node_tree", None)
será None
em ambos os casos. IMO, isso "supera" usando a árvore de nó e, em seguida, o teste de atributo de nome. None
não tem nada, se soubermos que não é nenhum, testar mais atributos pareceria supérfluo Também pode garantir que, se uma árvore de nó não for, None
ela terá um nome .bpy.types.ShaderNodeTree.name
script de teste
Usando o acima com o "teste duplo" para um nó sendo do 'GROUP'
tipo verificação, ele possui uma árvore de nó não nula.
Faça um dicionário, com chaves correspondentes ao nome do grupo de nós, contendo uma lista de nomes de materiais e tuplas de nomes de nós.
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)
Resultado.
Arquivo com 1 grupo de nós "Test_Material", 2 materiais "TestMat" e "TestMat.001".
O grupo de nós é usado em ambos os materiais com o nome "Grupo" em ambos.
['Test_Material']
defaultdict(<class 'list'>, {'Test_Material': [('TestMat', 'Group'), ('TestMat.001', 'Group')]})
Notas:
Cuidado ao igualar True
ou False
em testes. Por padrão, python iguala a maioria dos tipos a True ou false. Alguns exemplos de false são None
, o inteiro 0
e uma lista vazia[]
Métodos como hasattr
return True
ouFalse
if hasattr(foo, "bar") == True:
se foo.bar
existir, isso parece um pouco semelhante a
if True == True:
em vez disso, simplesmente use
if hasattr(foo, "bar"):
Alterar ligeiramente acima para retornar falso booleano em vez de nenhum quando o nó não tiver o atributo node_tree if nt:
será falso em ambos os casos, mas podemos discernir entre os dois.
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")
Baseado no comentário 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':