Bagaimana cara memeriksa apakah properti node bukan None saat melakukan iterasi melalui material?

Aug 17 2020

Saya mengalami kesalahan tanpa atribut saat melakukan iterasi melalui node dan nodegroups di beberapa file campuran.

Kesalahan: AttributeError: Objek 'NoneType' tidak memiliki atribut 'nama'

Bagaimana cara memeriksa apakah objek tidak memiliki properti 'nama' dan melewatinya?

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

Jawaban

3 batFINGER Aug 17 2020 at 17:41

Atribut bisa None

Kesalahan NoneType has no attributeini adalah kesalahan umum yang terlihat pada skrip blender. Misalnya bisa jadi itu kasusnyacontext.object is None

Untuk OP akan merekomendasikan mengedit judul pertanyaan untuk mencerminkan pesan kesalahan ini lebih-lebih.

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

yang dilemparkan node.node_tree.name == 'NodeGroupName'adalah menginformasikan node.node_treememiliki nilai None. Dapat menguji untuk kasus ini, yaitu

if node.node_tree is  None:

sebagai lawan

if hasattr(node, "node_tree"):

Keduanya akan benar ketika pohon simpul berada None

Sebenarnya adalah kasus yang aneh bahwa kode yang dimaksud akan menampilkan kesalahan ini, karena saya belum mengetahui (belum) tentang cara menambahkan node grup dan tidak memiliki node_tree yang terhubung. Berspekulasi bahwa ini adalah hasil dari menghapus grup node dari bpy.data.node_groupsyang merupakan node dari pohon node material ..

karenanya baris terakhir dari skrip pertanyaan bisa jadi

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

sejak merantai dan berhenti dulu False

Menggunakan getattr

Karena kami akan memperlakukan baik menggunakan atribut get yang sama dengan default argumen ketiga

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

akan berada Nonedalam kedua kasus tersebut. IMO ini "mengalahkan" menggunakan kedua pohon simpul has kemudian tes atribut nama. Nonetidak memiliki apa-apa, jika kita tahu tidak ada pengujian lebih lanjut untuk atribut akan tampak berlebihan. Dapat juga memastikan bahwa jika pohon simpul tidak, Noneia akan memiliki nama .bpy.types.ShaderNodeTree.name

Uji skrip

Menggunakan di atas dengan "tes ganda" untuk sebuah node yang 'GROUP'bertipe periksa itu memiliki pohon node bukan tidak ada.

Buatlah kamus, dengan kunci yang cocok dengan nama grup node yang berisi daftar nama material, nama node tupples.

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) 

Keluaran.

File dengan 1 grup node "Test_Material", 2 material "TestMat" dan "TestMat.001".

Grup node digunakan di kedua materi dengan nama "Grup" di keduanya.

['Test_Material']

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

Catatan:

Waspadalah dalam menyamakan Trueatau Falsedalam ujian. Secara default python menyamakan sebagian besar tipe dengan True atau false. Beberapa contoh salah adalah None, bilangan bulat 0dan daftar kosong[]

Metode seperti hasattrreturn baik TrueatauFalse

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

jika foo.barada ini dibaca agak mirip dengan

if True == True:

alih-alih cukup gunakan

if hasattr(foo, "bar"):

Mengubah sedikit di atas untuk mengembalikan boolean false alih-alih tidak ada ketika node tidak memiliki atribut node_tree, if nt:akan menjadi salah dalam kedua kasus, tetapi kita dapat membedakan keduanya.

        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

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