จะตรวจสอบได้อย่างไรว่าคุณสมบัติของโหนดไม่ใช่ None ในขณะที่ทำซ้ำผ่านวัสดุ?

Aug 17 2020

ฉันพบข้อผิดพลาดไม่มีแอตทริบิวต์ในขณะที่วนซ้ำผ่านโหนดและกลุ่มโหนดในไฟล์ผสมบางไฟล์

ข้อผิดพลาด: AttributeError: วัตถุ 'NoneType' ไม่มีแอตทริบิวต์ 'name'

ฉันจะตรวจสอบได้อย่างไรว่าออบเจ็กต์ไม่มีคุณสมบัติ "ชื่อ" และข้ามไป

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

คำตอบ

3 batFINGER Aug 17 2020 at 17:41

แอตทริบิวต์สามารถ None

ข้อผิดพลาดNoneType has no attributeนี้เป็นข้อผิดพลาดทั่วไปที่พบในสคริปต์ของเครื่องปั่น เช่นอาจเป็นกรณีที่context.object is None

สำหรับ OP ขอแนะนำให้แก้ไขชื่อคำถามเพื่อแสดงข้อความแสดงข้อผิดพลาดนี้มากขึ้น

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

โยนโดยnode.node_tree.name == 'NodeGroupName'มีการแจ้งมีค่าnode.node_tree Noneสามารถทดสอบในกรณีนี้ได้เช่น

if node.node_tree is  None:

ตรงข้ามกับ

if hasattr(node, "node_tree"):

ทั้งสองจะเป็นจริงเมื่อโหนดทรี None

เป็นกรณีที่แปลกจริงๆที่โค้ดที่เป็นปัญหาจะทำให้เกิดข้อผิดพลาดนี้เนื่องจากฉันไม่ทราบวิธีการเพิ่มโหนดกลุ่มและไม่มี node_tree ที่เชื่อมโยง คาดเดาว่านี่เป็นผลมาจากการลบกลุ่มโหนดจากbpy.data.node_groupsที่เป็นโหนดของโหนดทรีวัสดุ ..

ดังนั้นสคริปต์คำถามบรรทัดสุดท้ายอาจเป็นได้

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

ตั้งแต่การผูกมัดและสิ้นสุดในครั้งแรก False

การใช้ getattr

เนื่องจากเราค่อนข้างจะปฏิบัติเหมือนกันโดยใช้ get attribute กับอาร์กิวเมนต์เริ่มต้นที่สาม

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

จะเป็นNoneในทั้งสองกรณี IMO นี้ "สำคัญกว่า" โดยใช้ทั้งมีโหนดทรีจากนั้นมีการทดสอบแอตทริบิวต์ชื่อ Noneมีอะไรถ้าเรารู้ว่ามันไม่มีการทดสอบเพิ่มเติมสำหรับแอตทริบิวต์จะดูเหมือนฟุ่มเฟือยนอกจากนี้ยังสามารถตรวจสอบให้แน่ใจว่าถ้าต้นไม้โหนดไม่ได้Noneมันจะมีชื่อbpy.types.ShaderNodeTree.name

สคริปต์ทดสอบ

การใช้ข้างต้นกับ "การทดสอบสองครั้ง" สำหรับโหนดที่เป็น'GROUP'ประเภทตรวจสอบว่ามีโหนดที่ไม่ใช่ไม่มี

สร้างพจนานุกรมโดยใช้คีย์ที่ตรงกับชื่อกลุ่มโหนดที่มีรายการชื่อวัสดุชื่อโหนด 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) 

เอาท์พุท.

ไฟล์ที่มี 1 กลุ่มโหนด "Test_Material", 2 วัสดุ "TestMat" และ "TestMat.001"

กลุ่มโหนดถูกใช้ในวัสดุที่มีชื่อ "Group" ทั้งสองอย่าง

['Test_Material']

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

หมายเหตุ:

ระวังการเทียบเคียงTrueหรือFalseในการทดสอบ โดยค่าเริ่มต้น python จะกำหนดประเภทส่วนใหญ่เป็น True หรือ false ตัวอย่างบางส่วนของเท็จคือNoneจำนวนเต็ม0และรายการว่าง[]

วิธีการเช่นhasattrreturn อย่างใดอย่างหนึ่งTrueหรือFalse

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

หากfoo.barมีอยู่สิ่งนี้จะอ่านคล้ายกับ

if True == True:

แทนที่จะใช้

if hasattr(foo, "bar"):

การเปลี่ยนแปลงด้านบนเล็กน้อยเพื่อส่งคืนบูลีนเท็จแทนที่จะเป็นไม่มีเมื่อโหนดไม่มีแอตทริบิวต์ node_tree if nt:จะเป็นเท็จในทั้งสองกรณี แต่เราสามารถแยกแยะระหว่างสองสิ่งนี้ได้

        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

จากความคิดเห็นของ 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':