Como verificar se a propriedade do nó não é None durante a iteração por meio de materiais?

Aug 17 2020

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

3 batFINGER Aug 17 2020 at 17:41

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_treetem 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_groupsque 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á Noneem ambos os casos. IMO, isso "supera" usando a árvore de nó e, em seguida, o teste de atributo de nome. Nonenã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, Noneela 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 Trueou Falseem testes. Por padrão, python iguala a maioria dos tipos a True ou false. Alguns exemplos de false são None, o inteiro 0e uma lista vazia[]

Métodos como hasattrreturn TrueouFalse

if hasattr(foo, "bar") == True:

se foo.barexistir, 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")
0451 Aug 17 2020 at 04:14

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':