재료를 반복하는 동안 노드 속성이 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_treeNone

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

연결 ands가 먼저 중단되기 때문에 False

사용 getattr

세 번째 인수 기본값과 함께 get 속성을 사용하여 거의 동일하게 처리하므로

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

None두 경우 모두에서. IMO는 has 노드 트리를 모두 사용하여 "우수"한 다음 이름 속성 테스트가 있습니다. None아무것도 가지고 있지 않다는 것을 알고 있다면 속성에 대한 더 이상 테스트가 불필요 해 보일 것입니다. 또한 노드 트리가 아닌 None경우 이름 이 있는지 확인할 수 있습니다 .bpy.types.ShaderNodeTree.name

테스트 스크립트

노드 'GROUP'유형 검사에 대해 "이중 테스트"와 함께 위를 사용하면 non none 노드 트리가 있습니다.

재료 이름, 노드 이름 튜플 목록을 포함하는 노드 그룹 이름과 일치하는 키로 사전을 만듭니다.

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) 

산출.

노드 그룹 "Test_Material"1 개, 재료 "TestMat"및 "TestMat.001"2 개가있는 파일.

노드 그룹은 두 재료 모두에서 "그룹"이라는 이름으로 사용됩니다.

['Test_Material']

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

메모:

테스트 와 동등 True하거나 False테스트에서 조심하십시오 . 기본적으로 파이썬은 대부분의 유형을 True 또는 False와 동일시합니다. false의 몇 가지 예는 None, 정수 0및 빈 목록입니다.[]

같은 방법 hasattr반환하거나 True또는False

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

경우에 foo.bar존재하는이 다소 유사 읽고

if True == True:

대신 단순히 사용

if hasattr(foo, "bar"):

노드에 node_tree 속성이 없을 때 none 대신 boolean false를 반환하도록 약간 변경하면 if nt:두 경우 모두 false가되지만 둘을 구분할 수 있습니다.

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