> ## Documentation Index
> Fetch the complete documentation index at: https://dripart-mintlify-b90d3c69.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 속성

> 커스텀 노드의 속성

### 간단한 예제

다음은 이미지 반전 노드의 코드로, 커스텀 노드 개발의 핵심 개념을 살펴볼 수 있습니다.

```python theme={null}
class InvertImageNode:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": { "image_in" : ("IMAGE", {}) },
        }

    RETURN_TYPES = ("IMAGE",)
    RETURN_NAMES = ("image_out",)
    CATEGORY = "examples"
    FUNCTION = "invert"

    def invert(self, image_in):
        image_out = 1 - image_in
        return (image_out,)
```

### 주요 속성

모든 커스텀 노드는 Python 클래스이며, 다음과 같은 주요 속성을 갖습니다:

#### INPUT\_TYPES

이름에서 알 수 있듯이 `INPUT_TYPES`는 노드의 입력을 정의합니다. 이 메서드는 반드시 `required` 키를 포함한 `dict`를 반환하며, `optional` 및/또는 `hidden` 키도 포함할 수 있습니다. `required`와 `optional` 입력의 유일한 차이점은 `optional` 입력은 연결되지 않은 채로 둘 수 있다는 것입니다. `hidden` 입력에 대한 자세한 내용은 [숨겨진 입력](./more_on_inputs#hidden-inputs)을 참조하세요.

각 키의 값으로는 또 다른 `dict`가 있으며, 여기서 키-값 쌍은 입력의 이름과 유형을 지정합니다. 유형은 `tuple`로 정의되며, 첫 번째 요소는 데이터 유형을, 두 번째 요소는 추가 매개변수의 `dict`입니다.

여기서는 `image_in`이라는 이름의 필수 입력 하나만 있고, 유형은 `IMAGE`이며 추가 매개변수는 없습니다.

다음 몇 가지 속성과 달리, 이 `INPUT_TYPES`는 `@classmethod`입니다. 이렇게 하면 드롭다운 위젯의 옵션들(예를 들어 로드할 체크포인트의 이름)을 Comfy가 실행 시점에 계산할 수 있도록 합니다. 이에 대해서는 나중에 더 자세히 설명하겠습니다. {/* TODO link when written */}

#### RETURN\_TYPES

노드가 반환하는 데이터 유형을 정의하는 `str`의 `tuple`. 노드에 출력이 없더라도 이는 반드시 제공되어야 합니다. `RETURN_TYPES = ()`
<Warning>출력이 딱 하나인 경우, 뒤에 쉼표를 기억하세요: `RETURN_TYPES = ("IMAGE",)`. 이는 Python이 이를 `tuple`로 인식하도록 하기 위해 필요합니다.</Warning>

#### RETURN\_NAMES

출력을 레이블링하는 데 사용될 이름들입니다. 선택사항이며, 생략하면 이름은 단순히 `RETURN_TYPES`를 소문자로 바꾼 것입니다.

#### CATEGORY

ComfyUI **노드 추가** 메뉴에서 노드를 찾을 수 있는 위치입니다. 하위 메뉴는 경로로 지정할 수 있으며, 예를 들어 `examples/trivial`처럼 가능합니다.

#### FUNCTION

노드가 실행될 때 호출해야 하는 클래스 내 Python 함수의 이름입니다.

함수는 명명된 인수로 호출됩니다. 모든 `required`(및 `hidden`) 입력이 포함되며, `optional` 입력은 연결된 경우에만 포함되므로 함수 정의에서 기본값을 제공하거나 `**kwargs`로 포착해야 합니다.

함수는 `RETURN_TYPES`에 해당하는 튜플을 반환합니다. 아무것도 반환하지 않아도 이는 반드시 필요합니다(`return ()`). 다시 한번 말씀드리지만, 출력이 하나뿐인 경우 뒤에 쉼표를 기억하세요: `return (image_out,)`!

### 실행 제어 추가 기능

Comfy의 훌륭한 기능 중 하나는 출력을 캐시하고, 이전 실행과 다른 결과를 낼 수 있는 노드만 실행한다는 점입니다. 이는 많은 워크플로우를 크게 가속화할 수 있습니다.

본질적으로 이는 어떤 노드가 출력을 생성하는지 식별하고(특히 이미지 미리보기 및 이미지 저장 노드는 항상 실행됨), 이후 역방향으로 작업하여 마지막 실행 이후 변경되었을 수 있는 데이터를 제공하는 노드를 식별합니다.

커스텀 노드의 두 가지 선택적 기능이 이 과정을 돕습니다.

#### OUTPUT\_NODE

기본적으로 노드는 출력으로 간주되지 않습니다. `OUTPUT_NODE = True`로 설정하면 출력임을 명시할 수 있습니다.

#### IS\_CHANGED

기본적으로 Comfy는 노드의 입력이나 위젯이 변경되면 노드가 변경되었다고 간주합니다. 일반적으로 이는 정확하지만, 예를 들어 노드가 난수를 사용하거나(시드를 지정하지 않는 것이 좋으며, 이 경우 사용자가 재현성을 제어하고 불필요한 실행을 피할 수 있도록 시드 입력을 제공하는 것이 좋습니다), 외부에서 변경될 수 있는 입력을 로드하거나, 때때로 입력을 무시하는 경우(그래서 입력이 변경되었다고 해서 실행할 필요가 없는 경우) 이 기능을 오버라이드해야 할 수 있습니다.

<Warning>이름에도 불구하고, IS\_CHANGED는 `bool`을 반환해서는 안 됩니다</Warning>

`IS_CHANGED`는 `FUNCTION`에 의해 정의된 메인 함수와 동일한 인수를 전달받으며, 임의의 Python 객체를 반환할 수 있습니다. 이 객체는 이전 실행에서 반환된 것과 비교되며, `is_changed != is_changed_old`인 경우 노드가 변경된 것으로 간주됩니다(이 코드는 `execution.py`에 있으니 필요하다면 확인해 보세요).

`True == True`이므로, 변경되었다고 `True`를 반환하는 노드는 변경되지 않은 것으로 간주됩니다! 이는 Comfy 코드를 변경하면 기존 노드가 깨질 수 있기 때문에 그렇게 되지 않을 거라 확신합니다.

노드가 항상 변경된 것으로 간주되도록 지정하려면(가능하면 피해야 함, Comfy가 실행할 내용을 최적화하는 것을 막기 때문), `return float("NaN")`을 반환하세요. 이는 `NaN` 값을 반환하며, 이는 다른 `NaN`과도 같지 않습니다.

실제로 변경 여부를 확인하는 좋은 예는 내장된 LoadImage 노드의 코드로, 이미지를 로드하고 해시를 반환합니다.

```python theme={null}
    @classmethod
    def IS_CHANGED(s, image):
        image_path = folder_paths.get_annotated_filepath(image)
        m = hashlib.sha256()
        with open(image_path, 'rb') as f:
            m.update(f.read())
        return m.digest().hex()
```

#### SEARCH\_ALIASES

선택사항. 사용자가 이 노드를 찾을 때 검색할 수 있는 대체 이름 목록입니다. 이는 `/object_info` API 응답에서 `search_aliases`로 포함됩니다.

```python theme={null}
SEARCH_ALIASES = ["text concat", "join text", "merge strings"]
```

### 기타 속성

노드의 기본 Comfy 처리를 수정하는 데 사용할 수 있는 세 가지 속성이 더 있습니다.

#### INPUT\_IS\_LIST, OUTPUT\_IS\_LIST

이들은 데이터의 순차적 처리를 제어하는 데 사용되며, [나중에](./lists) 설명됩니다.

### VALIDATE\_INPUTS

클래스 메서드 `VALIDATE_INPUTS`가 정의되면 워크플로우가 실행되기 전에 호출됩니다. `VALIDATE_INPUTS`는 입력이 유효한 경우 `True`를 반환하거나, 오류를 설명하는 메시지(문자열 형태)를 반환해야 합니다(이 경우 실행이 방지됩니다).

#### 상수 검증

<Warning>`VALIDATE_INPUTS`는 워크플로우 내에서 상수로 정의된 입력만 받습니다. 다른 노드로부터 받는 입력은 `VALIDATE_INPUTS`에서 사용할 수 없습니다.</Warning>

`VALIDATE_INPUTS`는 서명이 요청하는 입력만 받습니다(즉, `inspect.getfullargspec(obj_class.VALIDATE_INPUTS).args`에서 반환된 입력). 이런 방식으로 받는 입력은 기본 검증 규칙을 통과하지 않습니다. 예를 들어 다음 코드 조각에서는 프론트엔드가 `foo` 입력의 지정된 `min` 및 `max` 값을 사용하지만 백엔드는 이를 강제하지 않습니다.

```python theme={null}
class CustomNode:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": { "foo" : ("INT", {"min": 0, "max": 10}) },
        }

    @classmethod
    def VALIDATE_INPUTS(cls, foo):
        # YOLO, 무엇이든 가능!
        return True
```

또한, 함수가 `**kwargs` 입력을 받는 경우, 가능한 모든 입력을 받게 되며, 이 모든 입력은 명시적으로 지정된 것처럼 검증을 건너뜁니다.

#### 유형 검증

`VALIDATE_INPUTS` 메서드가 `input_types`라는 이름의 인수를 받으면, 각 입력의 이름이 다른 노드의 출력과 연결된 상태에서 그 출력의 유형을 나타내는 딕셔널이 전달됩니다.

이 인수가 존재하면 기본 입력 유형 검증은 모두 건너뜁니다. 다음은 프론트엔드가 여러 유형을 지정할 수 있다는 사실을 활용한 예시입니다:

```python theme={null}
class AddNumbers:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "input1" : ("INT,FLOAT", {"min": 0, "max": 1000})
                "input2" : ("INT,FLOAT", {"min": 0, "max": 1000})
            },
        }

    @classmethod
    def VALIDATE_INPUTS(cls, input_types):
        # input1과 input2의 min과 max는 여전히 검증됩니다
        # 우리는 input1과 input2를 인수로 받지 않았기 때문입니다
        if input_types["input1"] not in ("INT", "FLOAT"):
            return "input1은 INT 또는 FLOAT 유형이어야 합니다"
        if input_types["input2"] not in ("INT", "FLOAT"):
            return "input2은 INT 또는 FLOAT 유형이어야 합니다"
        return True
```
