¿Cómo verificar si la propiedad del nodo no es Ninguna mientras se itera a través de los materiales?

Aug 17 2020

Me encuentro con un error sin atributo al iterar a través de nodos y grupos de nodos en algunos archivos combinados.

Error: AttributeError: el objeto 'NoneType' no tiene atributo 'name'

¿Cómo verificaría si los objetos no tienen la propiedad 'nombre' y lo omitiría?

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

Respuestas

3 batFINGER Aug 17 2020 at 17:41

Un atributo puede serNone

El error NoneType has no attributees un error común que se ve en las secuencias de comandos de Blender. Por ejemplo puede darse el caso de quecontext.object is None

Al OP recomendaría editar el título de la pregunta para reflejar más este mensaje de error.

Error: AttributeError: 'NoneType' object has no attribute 'name'

lanzado por node.node_tree.name == 'NodeGroupName'está informando node.node_treetiene el valor None. Puede probar que este sea el caso, es decir

if node.node_tree is  None:

Opuesto a

if hasattr(node, "node_tree"):

Ambos serán verdaderos cuando el árbol de nodos seaNone

En realidad, es un caso extraño que el código en cuestión arroje este error, ya que no sé (todavía) cómo agregar un nodo de grupo y no tengo un nodo_árbol vinculado. Especule que esto es el resultado de eliminar un grupo de nodos bpy.data.node_groupsque era un nodo de un árbol de nodos materiales.

por lo tanto, la última línea del guión de preguntas podría ser

if (node.type in ["GROUP"]  
        and node.node_tree 
        and node.node_tree.name == 'NodeGroupName'
        ):

ya que encadenar ands cesa en primer lugarFalse

Usandogetattr

Dado que prácticamente trataríamos de la misma manera usando el atributo get con el tercer argumento predeterminado

node_tree = getattr(node, "node_tree", None)

será Noneen ambos casos. En mi opinión, esto "triunfa" usando tanto el árbol de nodos como la prueba de atributo de nombre. Noneno tiene nada, si sabemos que no es ninguno, parecería superfluo seguir probando los atributos . También podemos asegurar que si un árbol de nodos no Nonelo es, tendrá un nombre .bpy.types.ShaderNodeTree.name

Guión de prueba

Usando lo anterior con la "doble prueba" para que un nodo sea de 'GROUP'tipo, verifique que no tenga un árbol de nodos.

Haga un diccionario, con claves que coincidan con el nombre del grupo de nodos que contenga una lista de nombres de materiales, tuplas de nombres de nodos.

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) 

Producción.

Archivo con 1 grupo de nodos "Test_Material", 2 materiales "TestMat" y "TestMat.001".

El grupo de nodos se utiliza en ambos materiales con el nombre "Grupo" en ambos.

['Test_Material']

defaultdict(<class 'list'>, {'Test_Material': [('TestMat', 'Group'), ('TestMat.001', 'Group')]})

Notas:

Cuidado con equiparar Trueo Falseen pruebas. Por defecto, Python equipara la mayoría de los tipos con True o false. Algunos ejemplos de false son None, el entero 0y una lista vacía[]

Métodos como hasattrreturn Trueo bienFalse

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

si foo.barexiste esto se lee algo parecido a

if True == True:

en su lugar, simplemente use

if hasattr(foo, "bar"):

Cambiar ligeramente lo anterior para devolver boolean false en lugar de none cuando el nodo no tiene el atributo node_tree, if nt:será falso en ambos casos, pero podemos discernir entre los dos.

        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

Basado en el comentario 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':