테마
Python 람다·클래스·함수
Python의 함수와 클래스 문제는 값이 어디에 저장되고 누구와 공유되는지를 추적하는 문제다. 이 문서는 람다(lambda)와 map·filter, 기본값 매개변수, 인자 전달, 그리고 클래스(class)·상속(inheritance)·오버라이딩(overriding)을 Python 3 기준으로 정리한다.
람다와 map·filter
람다는 lambda 매개변수: 식 모양의 이름 없는 한 줄 함수다. def로 이름을 붙일 만큼 크지 않은 계산을 다른 함수에 바로 넘길 때 쓰므로 map·filter·sorted(key=...)와 자주 함께 나온다.
map(함수, 모음)은 모든 요소에 함수를 적용하고, filter(함수, 모음)는 결과가 참인 요소만 남긴다. 둘 다 값을 하나씩 꺼내 주는 객체를 돌려주므로 list()로 감싸야 내용이 보인다.
python
f = lambda x, y=2: x ** y
print(f(3), f(2, 3)) # 9 8
print(list(map(lambda x: x * 10, [1, 2, 3]))) # [10, 20, 30]
print(list(filter(lambda x: x > 1, [1, 2, 3]))) # [2, 3]인자 전달과 기본값 함정
Python은 인자로 객체를 가리키는 참조를 넘긴다. 그래서 함수 안에서 리스트에 append하면 호출한 쪽 리스트도 바뀐다. 반면 정수나 문자열은 바꿀 수 없는 값이라 n += 1은 함수 안의 이름이 새 값을 가리키게 할 뿐이고 바깥 변수는 그대로다. k = [0]; m = 5를 넘겨 lst.append(n); n += 1을 하면 k는 [0, 5], m은 5로 남는다.
기본값 매개변수는 함수를 정의할 때 한 번만 만들어진다. 기본값을 리스트 같은 가변 객체로 두면 호출마다 같은 리스트가 재사용되어 값이 누적된다. 안전하게 하려면 기본값을 None으로 두고 함수 안에서 새 리스트를 만든다.
python
def add(item, box=[]):
box.append(item); return box
print(add(1), add(2)) # [1, 2] [1, 2]두 호출이 같은 리스트를 돌려주므로 둘 다 [1, 2]로 찍힌다.
클래스와 self
클래스는 데이터와 동작을 묶은 설계도다. __init__은 객체를 만들 때 자동으로 불리는 초기화 메서드다. 메서드의 첫 매개변수 self는 지금 호출된 객체 자신을 가리킨다. Python은 이를 자동으로 넘겨 주므로, a.show()처럼 부를 때는 self 자리를 비워 둔다.
self.n처럼 객체에 붙인 인스턴스(instance) 변수는 객체마다 따로 있고, 클래스 본문에 쓴 클래스 변수는 모든 객체가 공유해 객체 수를 세는 데 쓴다. 단 메서드 안에서 self.v = 5처럼 대입하면 클래스 변수 v가 바뀌지 않고 그 객체에만 같은 이름의 인스턴스 변수(instance variable)가 새로 생긴다. 공유 값을 바꾸려면 A.cnt += 1처럼 클래스 이름으로 쓴다.
상속과 super
상속은 class B(A):처럼 괄호에 부모 클래스를 적어 부모의 속성과 메서드를 물려받는 것이다. 자식이 같은 이름의 메서드를 다시 정의하면 오버라이딩이 되어 자식 것이 실행된다. 자식이 __init__을 새로 쓰면 부모 __init__은 자동으로 불리지 않으므로, 필요하면 super().__init__(...)로 직접 부른다. __str__은 print(객체)나 str(객체)가 보여 줄 문자열을 정한다.
python
class A:
cnt = 0
def __init__(self, n):
self.n = n; A.cnt += 1
def show(self): return "A" + str(self.n)
def __str__(self): return f"<{self.n}>"
class B(A):
def __init__(self, n): super().__init__(n * 2)
def show(self): return "B" + str(self.n)
x, y = A(1), B(1)
print(x.show(), y.show(), A.cnt, y) # A1 B2 2 <2>B(1)은 super().__init__(2)로 n이 2가 되고, y.show()는 B의 것이, print(y)는 물려받은 __str__이 실행된다.
시험 포인트
lambda x: 식→ 이름 없는 한 줄 함수.map은 모두 변환,filter는 참인 것만.list()로 감싸야 보인다.- 리스트 인자는 함수 안에서 바꾸면 밖도 바뀌고, 가변 기본값(
box=[])은 호출 사이에 누적된다. self= 호출된 객체. 인스턴스 변수는 객체마다, 클래스 변수는 공유.- 자식
__init__이 있으면 부모__init__은super().__init__()으로 직접 불러야 실행된다.
