초보 개발자

26강 스페셜 메소드 본문

Python/윤성우 열혈 파이썬

26강 스페셜 메소드

taehyeki 2022. 1. 18. 14:27

[스페셜 메소드]

다음과 같은 형태의 이름을 가지면서 파이썬에 의해 호출되는(프로그래머가 그 이름을 직접 명시하여 호출하지 않는) 메소드를 가리켜 '스페셜 메소드'라 한다.

 

__name__

 

가장 대표적인 스페셜 메소드로 __init__이 있다. 이는 객체 생성시 자동으로 호출되는 메소드이다.

그리고 다음은 우리가 호출해본 경험이 있는 스페셜 메소드들이다.

 

__len__  :  len 함수가 호출되었을 때 호출 됨

__iter__  :  iter 함수가 호출되었을 때 호출 됨

__str__  :  str 함수가 호출되었을 때 호출 됨

 

우리가 iter(s)를 호출하면 실제로 파이썬은 s.__iter__() 이렇게 호출을 한다.

약속이다.

 

len(s) -> s.__len__()

str(s) -> s.__str__()

 

위와같이 사용해도 상관은 없다. 하지만 굳이..?

 

[클래스에 스페셜 메소드 정의하기]

class Car:
    def __init__(self,id):
        self.id = id
    def __len__(self):
        return len(self.id)
    def __str__(self):
        return 'Vehicle number: ' + self.id

def main():
    c = Car('12가1234')
    print(len(c)) # c.__len__() 호출 -> len(self.id) -> self.id__len__() 호출 7 반환
    print(str(c)) # c.__str__() 호출 -> 'Vihecle number : 12가 1234반환'

main()

 

이렇게 클래스 안에 스페셜 메소드를 정의해주면 기존 스페셜메소드의 오버라이딩이 되어진다.

만약 

def __str__(self):
    return '안녕하세요'

 

라고 적는다면 이제 str(c)는 c.__str__()를 호출하는데 우리는 __str__을 안녕하세요 라고 return값을 바꾸었으니 이제 안녕하세요라고만 출력이 되는 것이다. 

 

__len__은 다른건 잘 안됨)

 

[iterable 객체가 되게끔 하기]

iter함수의 인자로 전달이 가능한 객체를 가리켜 iterable객체라고 한다. iter은 iterator 객체를 반환해야한다.

next함수의 인자로 전달이 가능한 객체를 가리켜 iterator객체라고 한다.

 

iterable 객체의 조건 : 스페셜 메소드인 __iter__가 존재해야 한다.

iterator 객체의 조건 : 스페셜 메소드인 __next__가 존재해야 한다.

 

class Car:
    def __init__(self,id):
        self.id = id
    def __iter__(self):
    	return iter(self.id) # 변수 id의 iterator 객체를 반환
        #self.id__iter__() 로 이어지고 이걸 반환

def main():
    c = Car('12가1234')
    for i in c: # Car객체가 iterable 객체라는 증거
    	print(i, end = ' ')
        

main()
1 2 가 1 2 3 4

 

위의 메소드가 반환하는 iterator 객체는 self.id의 iterator객체이다. 따라서 매우 간단한 구현이라 할 수 있다.

그래도 이로 인해서 __iter__메소드는 iteratro객체를 반환해야한다. 는 조건을 만족시켰다.

때문에 car객체는 iterable객체이다. 이는 car객체를 대상으로 for 루프를 구성할 수 있다는 사실로도 확인할 수 있다.

 

car클래스는 __iter__라는 메소드를 가지고 있다. iterator객체를 반환하는 역할을 한다.

따라서 car클래스는 iterable객체이다. iter안에 들어갈 수 있기 때문에..

 

누군가 iter( c(car클래스의 객체)) 를 했을 때 c.__iter__()를 할 테고, 그럼 iter(self.id)가 호출이되고 id의 값은 문자열이니까 iterable객체이므로 self.id.__iter.__() 을 사용하여 iterator객체를 반환하기 때문이다.

 

만약에 class안에 __iter__을 선언해주지 않았다면 일반 클래스의 객체가 됨으로 for 루프에 넣는다는건 상상도 못할일이다. for 루프로 사용할 수 있는 이유는 iter메서드를 선언해주었기 때문이다.

 

[iterator 객체가 되게끔 하기]

iterator 객체가 되게끔 하려면 __next__메소드를 가지고 있으면 된다.

그리고 실제 itrerator 객체로 사용할 수 있는 수준으로 메소드가 정의되어야 한다.

조건 1, 가지고 있는 값을 하나씩 반환한다.

조건 2, 더이상 반환할 값이 없는 경우 StopIteration 예외를 발생시킨다.

 

class Coll:
    def __init__(self,d):
        self.ds = d
        self.cc = 0
    def __next__(self):
        if len(self.ds) <= self.cc:
            raise StopIteration
        self.cc += 1
        return self.ds[self.cc - 1]

 

이렇게 구현할 수 있다. 비록 iter함수 호출이 아닌 방법으로 생성이 되었지만

이는 iterator 객체에 해당이 된다. next함수의 인자로 전달이 되어 저장된 값을 하나씩 반환할 뿐 아니라

더이상 반환할 값이 없으면 StropIteration예외도 발생 시키기 때문이다.

 

[iterator 객체이자 iterable 객체가 되게끔 하기]

 

class Coll:
    def __init__(self,d):
        self.ds = d
    def __next__(self):
        if len(self.ds) <= self.cc:
            raise StopIteration
        self.cc += 1
        return self.ds[self.cc - 1]
    def __iter__(self)
    	self.cc = 0
        return self

앞서 배운 것들을 하나로 묶으면 이렇게 표현할 수 있다.

c = coll([1,2,3,4])이렇게 처음 생성해두면

self.ds에 [1,2,3,4]가 들어있을 것이고

 

for i in c 를하면

for루프가 iter(c)를 할텐데 그럼 c.__iter__()이 실행이되고 cc에 는 0이 초기화, 그리고 자기 자신(ds,cc, __next__,__iter__을 가지고 있는 자신의 객체)을 반환한다. 그리고 이제 for가 next를 통해서 iter(c)를 next를 돌리는 형식이다.

 

즉 coll 객체는 그 자체로 __next__ 메소드를 갖는 iterator객체이다. 즉 Coll 객체는 __next__메소드를 iterator객체이자. 동시에 __iter__메소드를 갖는 iterable 객체이다. 그래서 coll의 __iter__ 메소드는 self를 반환한다. 

 

사이사이 print문을 넣어서 확인해보자

이렇게 잘 나타나는 걸 확인할 수 있다.

'Python > 윤성우 열혈 파이썬' 카테고리의 다른 글

28강 정보은닉과 __dict__  (0) 2022.01.24
27강 연산자 오버로딩  (0) 2022.01.24
24강 상속  (0) 2022.01.18
23강 클래스와 객체의 본질  (0) 2022.01.18
22강 메소드 기반 문자열 조합  (0) 2022.01.17