Menu
Coddy logo textTech

다형성이란 무엇인가요?

프로그래밍에서 다형성(polymorphism)은 함수 호출이나 메서드 이름 같은 하나의 코드가 서로 다른 타입의 값과 함께 동작하고, 각 타입이 자신만의 동작을 제공하는 능력입니다. shape.area()를 호출하면 원과 정사각형에서 서로 다른 계산이 실행됩니다.

글쓴이: Kevin Spektor, 공동 창업자, CTO

업데이트: 2026년 9월 24일

Python에서 len("hello")는 5를, len([4, 8, 15])는 3을, len({"a": 1})은 1을 반환해요. 함수 이름 하나를 세 타입에 쓰는데, 세는 방식은 타입마다 달라요. 문자열은 글자를, 리스트는 항목을, 딕셔너리는 키를 세죠. 이 단어는 그리스어에서 왔어요. poly는 여럿, morph는 형태라는 뜻이에요. 호출은 하나, 동작의 형태는 여럿이에요.

다형성은 어떻게 동작하나요

코드는 shape.area()처럼 이름으로 메서드를 호출해요. 그 줄이 실행될 때 언어는 실제 객체를 보고, 그 객체의 클래스에서 area를 찾아요. 이 탐색을 동적 디스패치(dynamic dispatch)라고 하며, 한 줄의 코드가 객체마다 다른 일을 하게 만드는 것이 바로 이거예요.

Circle 3.14
Square 9
Circle 12.57

Python은 먼저 객체의 클래스에서, 그다음 메서드 결정 순서(method resolution order)라는 정해진 순서에 따라 부모 클래스에서 메서드를 찾아요. Square에 자기 area()가 없다면 탐색은 Shape.area()에 도달해 NotImplementedError를 발생시켜요. 모든 하위 클래스가 이 메서드를 제공해야 한다는 신호예요.

반복문은 자신이 어떤 도형을 들고 있는지 전혀 확인하지 않아요. 삼각형을 추가하려면 자기 area()를 가진 Triangle 클래스를 작성하면 되고, 반복문은 그대로 동작해요. 다형성이 없다면 반복문에는 도형마다 if isinstance(...) 분기가 필요하고, 새 도형이 생길 때마다 고쳐야 해요.

다형성의 종류

종류다른 이름모습어떤 버전이 선택되는 시점
서브타입런타임 다형성, 메서드 오버라이딩하위 클래스가 부모의 메서드를 대체프로그램이 실행되는 동안
애드혹오버로딩이름 하나에 매개변수 타입별로 여러 버전, 연산자 오버로딩 포함Java와 C++에서는 컴파일 타임
매개변수제네릭, 템플릿어떤 타입에든 동작하는 코드 하나: Java의 List<T>, C++의 vector<T>컴파일 타임

객체지향 프로그래밍에서 별다른 설명 없이 "다형성"이라고 하면 거의 항상 첫 번째 줄, 즉 오버라이딩을 통한 서브타입 다형성을 뜻해요.

Python에는 세 가지가 모두 나름의 방식으로 있어요. 오버라이딩은 도형 예제처럼 동작해요. + 같은 연산자는 애드혹 다형성이에요. max()와 sorted() 같은 함수는 성격상 매개변수 다형성이에요. 항목끼리 비교할 수만 있으면 숫자, 문자열, 날짜 리스트를 모두 받으며, list[int]나 TypeVar 같은 타입 힌트로 이를 명시할 수도 있어요.

Java의 컴파일 타임 다형성과 런타임 다형성

Java에는 두 가지가 모두 있고, 면접에서 그 차이를 자주 물어요.

class Animal { String sound() { return "..."; } }
class Dog extends Animal {
    @Override String sound() { return "Woof"; }
}

Animal pet = new Dog();
pet.sound();          // "Woof": chosen at run time from the object

int add(int a, int b)          { return a + b; }
double add(double a, double b) { return a + b; }
add(2, 3);            // int version, chosen by the compiler
add(2.5, 1.0);        // double version

변수 pet의 타입은 Animal인데도 Dog 버전이 실행돼요. 선택이 변수가 아니라 객체에 따라 정해지기 때문이에요. 두 add 메서드는 오버로딩이에요. 컴파일러가 프로그램 실행 전에 인자 타입을 보고 하나를 골라요. 인터페이스는 코드를 공유하지 않고도 같은 런타임 동작을 제공해요. Comparable을 구현한 클래스라면 무엇이든 Collections.sort로 정렬할 수 있어요. C++도 같은 방식으로 동작하지만 한 가지가 달라요. 메서드가 virtual로 선언되어야만 런타임 디스패치가 적용돼요. Java의 다형성, 메서드 오버로딩, C++ 가상 함수를 참고하세요.

Python의 다형성: 덕 타이핑과 연산자

Python은 공통 부모 클래스를 요구하지 않아요. 객체에 코드가 호출하는 메서드가 있으면 동작해요. "오리처럼 걷고 오리처럼 꽥꽥거리면 오리다"라는 것이죠. 연산자도 다형적이에요. a + b라고 쓰면 a.__add__(b)가 호출되므로, 직접 만든 클래스도 +, len(), print()를 지원할 수 있어요.

3 abcd [1, 2]
Vector(11, 22)
5 3 2

상속은 다형성을 얻는 한 가지 방법일 뿐 필수 조건이 아니에요. Vector는 특별한 것을 상속하지 않았는데도 len()과 +가 이를 내장 타입처럼 다뤄요. Python 상속 문서에서 하위 클래스를 쓰는 방법을 볼 수 있어요.

흔한 실수

Python이 시그니처로 오버로딩하리라 기대하기. 같은 이름으로 두 번째 def를 쓰면 첫 번째를 조용히 대체해요.

Hi Ana Silva
Traceback (most recent call last):
  ...
TypeError: greet() missing 1 required positional argument: 'last'

대신 기본 인자를 쓰세요. def greet(first, last="")처럼요.

C++에서 virtual 빠뜨리기. 이것이 없으면 기반 클래스 포인터로 메서드를 호출할 때 객체가 하위 클래스여도 기반 클래스 버전이 실행돼요.

의미를 바꾸는 오버라이딩. 어떤 하위 클래스의 area()가 둘레를 반환한다면 area()를 믿는 모든 호출자가 망가져요. 오버라이딩은 부모가 한 약속을 지켜야 해요. 이 규칙을 리스코프 치환 원칙이라고 해요.

곳곳의 타입 검사. if type(x) == ... 분기가 줄줄이 이어진다면 보통 각 타입이 자기 메서드를 가져야 한다는 신호예요.

다음 단계

다형성은 각 객체의 데이터를 보호하는 캡슐화, 그리고 여러 타입이 구현하는 공통 인터페이스를 정의하는 추상화와 함께 동작해요. Python 클래스 문서에서 오버라이딩을 연습하거나, 오버로딩과 오버라이딩을 나란히 다루는 Java 강좌를 해 보세요.

자주 묻는 질문

다형성의 예로는 무엇이 있나요?
Python의 + 연산자예요. 1 + 2는 숫자를 더하고, "ab" + "cd"는 문자열을 이어 붙이고, [1] + [2]는 리스트를 이어 붙여요. 같은 기호가 세 타입에서 동작하고, 각 타입이 그 의미를 정해요. 객체지향 코드에서 대표적인 예는 도형 리스트로, 각 도형이 자기 공식으로 area()에 답해요.
다형성과 상속은 어떻게 다른가요?
상속은 클래스가 부모 클래스의 코드를 재사용하게 해요. 다형성은 코드가 서로 다른 타입을 하나의 공통 인터페이스로 다루게 해요. 하위 클래스가 부모의 메서드를 오버라이딩할 수 있으므로 상속은 다형성을 얻는 흔한 방법이지만, Python의 덕 타이핑과 Java의 인터페이스는 코드를 전혀 공유하지 않고도 다형성을 제공해요.
생물학에서 다형성은 무슨 뜻인가요?
생물학에서 다형성은 사람의 A, B, AB, O 혈액형처럼 한 집단 안에 어떤 형질이나 유전자의 형태가 두 가지 이상 존재하는 것을 뜻해요. "여러 형태"라는 그리스어 어원은 프로그래밍 용어와 같지만, 두 개념은 서로 관계가 없어요.
Python은 메서드 오버로딩을 지원하나요?
Java나 C++처럼 매개변수의 타입이나 개수로 오버로딩하지는 않아요. 같은 이름으로 두 번째 def를 쓰면 첫 번째를 대체해요. Python 코드는 기본 인자, *args, 또는 첫 번째 인자의 타입에 따라 함수를 고르는 functools.singledispatch로 같은 효과를 내요.
다형성은 왜 유용한가요?
타입을 사용하는 코드를 바꾸지 않고도 새 타입을 추가할 수 있게 해 주기 때문이에요. 모든 도형에 shape.draw()를 호출하는 그리기 프로그램은 삼각형 클래스를 추가해도 고칠 곳이 없고, 새 클래스만 작성하면 돼요. 다형성이 없다면 그 반복문에는 타입마다 새 if 분기가 늘어날 거예요.
Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기