포스트

[Python]1급 객체? (First-class citizen)

일급 객체?

컴퓨터 프로그래밍 언어 디자인에서, 일급 객체(first-class object)란 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가리킨다. 보통 함수에 인자로 넘기기, 수정하기, 변수에 대입하기와 같은 연산을 지원할 때 일급 객체라고 한다. (출처 : 위키백과1))

사실 자주 쓰이는 개념은 아니고, 아직도 논의가 이루어지는 개념입니다.

앞선 위키백과의 설명문을 로빈 포플스톤이 정의한 세부적인 항목으로 나타내면 다음과 같습니다.

  1. 모든 요소는 함수의 실제 매개변수가 될 수 있다.

  2. 모든 요소는 함수의 반환 값이 될 수 있다.

  3. 모든 요소는 할당 명령문의 대상이 될 수 있다.

  4. 모든 요소는 동일 비교의 대상이 될 수 있다.

다만, 아직도 일급 객체가 정확히 어떤 것인지 애매합니다.

현대적인 고급 언어에서는 일급 객체 요건을 만족하는 요소만을 객체라 부르기도 하기 때문입니다.


일반적으로 객체로 불릴 수 있는 것들을 나열해봅시다.

값, 기본 자료형, 복잡 자료형, 클래스, 함수(메서드)…

이 보다 더 많을 수 있지만, 일단 이 다섯을 중점적으로 설명해봅시다.

만약, 어떤 언어에서 어떤 변수를

함수의 매개 변수로 사용하고, 때론 함수의 반환값이 되며,

할당 명령문의 대상이 되고, 동일 비교의 대상이 된다면,

변수는 일급 객체의 요건을 만족합니다.

Python 코드로 알아보기

모든 것은 (일급 객체라고 해도 무방한)객체로 이루어진 파이썬에서는,

사실 정말 거의 모든 것이 일급 객체입니다.

10이라는 숫자조차도 원시 타입이 아닌 int라는 클래스로 지정됩니다.

아주 한정적으로 원시 타입 수를 쓸 수 있기도 하지만, 사실상 파이썬의 모든 객체는 일급객체 입니다.

기본, 복합 자료형의 경우

기본 자료형은 매우 간단합니다.

굳이 설명이 필요하지 않을 것 같지만, 코드로 나타낸다면 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
# 할당 명령문의 대상이 됨
x1 = 10 # Python에서는 10이란 정수 값도 참조 클래스 기반 객체입니다.
l1 = [1, 2] # 복합 자료형 List

def function(x):
    if x == 10 or x == [1, 2] # 동일 비교의 대상이 됨
        return x # 함수의 반환 값이 됨

x2 = function(x1) # 함수의 매개 변수가 됨
l2 = function(l1)

위의 코드는 매우 정상적으로 실행됩니다.

정수 자료형 x1과 복합 자료형 l1 모두 function 함수의 인자로 들어갈 수 있으며,

동일 비교(equals)의 대상이 되고,

함수의 반환 값으로 쓰일 수 있습니다.

함수(메서드)의 경우

Python에서 함수를 일급 객체 취급을 함으로써 가능한 것이 대표적으로 두 가지 있습니다.

  1. 데코레이터를 만들 때, 함수의 인자로 또다른 함수를 넣곤 합니다.

  2. 람다 표현식 자체가 함수를 일급 객체로 취급하기에 가능한 것이기도 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def deco(func):  # 함수의 매개 변수가 됨
    def wrapper():
        print("목표 함수 실행 이전")
        func()
        print("목표 함수 실행 이후")
    return wrapper # 함수의 반환 값이 됨

@deco
def hello():
    f = lambda x : print(f"{x} - hello world") # 변수에 람다 표현식(함수)를 할당 함
    f("cat") # 람다 함수에는 반드시 인자가 필요하기에 임시로 넣은 값입니다.

h = hello  # 함수를 축약한 변수에 대입해 활용할 수 있음
h()

print(h == hello)  # 함수 간에도 equals가 가능함

# 목표 함수 실행 이전
# cat - hello world
# 목표 함수 실행 이후
# True

함수 또한 다른 함수의 인자로 들어가거나, 반환값이 될 수 있고

함수 자체를 변수에 할당하거나 대소 비교가 가능합니다.

클래스의 경우

당연히 클래스도 가능합니다.

클래스 자체가 일반적으로 객체를 이르는 말이긴 합니다만,

클래스에 대한 참조도 객체로써 활용될 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Cat:
    def meow(self):
        print("Nyang")

Dog = Cat() # Cat의 인스턴스를 생성해 meow에 할당합니다.
Dog = Cat   # Cat 클래스에 대한 참조 자체를 할당합니다.

cat = Dog() # 이는 매우 정상적으로, Cat 클래스 인스턴스를 생성해 cat에 할당합니다.

cat.meow()  # Nyang

from typing import Type

def factory(Cls : Type[Cat] ): # Cat 클래스에 대한 참조를 넣습니다
    x = Cls()
    return x

cat2 = factory(Cat)

cat2.meow() # Nyang
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.