Làm thế nào để kiểm tra xem thuộc tính của nút không phải là Không trong khi lặp qua các vật liệu?

Aug 17 2020

Tôi đang gặp phải lỗi không có thuộc tính khi lặp qua các nút và nhóm nút trong một số tệp kết hợp.

Lỗi: AttributeError: Đối tượng 'NoneType' không có thuộc tính 'name'

Làm cách nào để kiểm tra nếu các đối tượng không có thuộc tính 'name' và bỏ qua nó?

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

Trả lời

3 batFINGER Aug 17 2020 at 17:41

Một thuộc tính có thể là None

Lỗi NoneType has no attributenày là một lỗi phổ biến thường thấy trong kịch bản máy xay sinh tố. Ví dụ, nó có thể là trường hợpcontext.object is None

Đối với OP khuyên bạn nên chỉnh sửa tiêu đề câu hỏi để phản ánh thông báo lỗi này nhiều hơn.

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

ném bởi node.node_tree.name == 'NodeGroupName'là thông báo node.node_treecó giá trị None. Có thể kiểm tra trường hợp này, tức là

if node.node_tree is  None:

như trái ngược với

if hasattr(node, "node_tree"):

Cả hai đều đúng khi cây nút None

Thực sự là một trường hợp kỳ lạ rằng mã được đề cập sẽ gây ra lỗi này, vì tôi chưa biết (chưa) về cách thêm nút nhóm và không có nút_tree được liên kết. Suy đoán đây là kết quả của việc xóa một nhóm nút khỏi bpy.data.node_groupsđó là một nút của cây nút vật liệu ..

do đó dòng câu hỏi cuối cùng của kịch bản có thể là

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

kể từ khi chuỗi ands chấm dứt vào đầu tiên False

Sử dụng getattr

Vì chúng ta sẽ xử lý giống nhau bằng cách sử dụng thuộc tính get với đối số thứ ba là mặc định

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

sẽ được Nonetrong cả hai trường hợp. IMO "át chủ bài" này bằng cách sử dụng cả cây nút có sau đó có kiểm tra thuộc tính tên. Nonekhông có gì, nếu chúng ta biết rằng không có thử nghiệm thêm cho các thuộc tính sẽ có vẻ thừa Cũng có thể đảm bảo rằng nếu không phải cây nút Nonethì nó sẽ có tên .bpy.types.ShaderNodeTree.name

Tập lệnh thử nghiệm

Sử dụng ở trên với "kiểm tra kép" cho một nút thuộc 'GROUP'loại kiểm tra xem nó có một cây không nút nào không.

Tạo một từ điển, với các khóa khớp với tên nhóm nút chứa danh sách tên vật liệu, tên nút.

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) 

Đầu ra.

Tập tin có 1 nhóm nút "Test_Material", 2 vật liệu "TestMat" và "TestMat.001".

Nhóm nút được sử dụng trong cả hai vật liệu với tên "Nhóm" trong cả hai.

['Test_Material']

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

Ghi chú:

Hãy coi chừng bằng Truehoặc Falsetrong các bài kiểm tra. Theo mặc định, python tương đương với hầu hết các loại thành True hoặc false. Một số ví dụ về false là None, số nguyên 0và danh sách trống[]

Các phương thức như hasattrreturn TruehoặcFalse

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

nếu foo.bartồn tại, điều này hơi giống với

if True == True:

thay vào đó chỉ cần sử dụng

if hasattr(foo, "bar"):

Thay đổi một chút ở trên để trả về boolean false thay vì không có khi nút không có thuộc tính node_tree, if nt:sẽ sai trong cả hai trường hợp, nhưng chúng ta có thể phân biệt giữa hai trường hợp.

        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

Dựa trên nhận xét của 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':