티스토리 뷰

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

연산자중복정의란?

연산자중복정의 설명에 앞서 우선 아래의 예를 먼저 보도록 하자

개발자가 방금만든 gstring이라는 문자열클래스가 있다이 문자열클래스의 특화된 기능으로 기존 문자열에서 입력받은 문자만 제외하는 기능이 있다물론 클래스메서드로 작성되었다하지만 팀장이 좀더 직관적으로 보이도록 '-'연산자를 사용해서 동작할수 있도록 수정하라고 한다팀장이 원하는 방법은 아래와 같다.

g = gstring('ABCDEFGabcdefg') #초기문자열

g.Remove('Adg'#메소드로 동작결과 : 'BCDEFGabcef'

g - 'Adg' #연산자로 동작결과 : 'BCDEFGabcef'

이러한 요구사항을 만족시키기 위하여 사용되는 것이 연산자 중복정의이다.

즉 사용자정의 객체에 대하여 필요한 연산자를 내장타입과 형태와 동작이 유사하도록 재정의하는것이다.

물론 이러한 기능을 클래스메서드로 구현할수 있다.

이러한 선택은 정의하는 클래스에 이터레이터기능을 추가하는것과 같이 정책적인 면과 개발자의 선호도에 의해서 결정된다연산자중복은 일반적으로 벡터나 행렬과 같은 수치연산에서 자주사용한다.

그럼 팀장의 요구사항에 맞게 gstring클래스를 작성하도록 해보겠다.

class gstring:

    def __init__(self,init=None): #생성자

        self.content=init

 

    def __sub__(self,str): #'-'연산자중복정의

        for i in str:

            self.content=self.content.replace(i,'')

        return gstring(self.content)

 

    def Remove(self,str): #Remove메서드는 '-'연산자중복과 동일하기에 '__sub__'를 재호출

        return self.__sub__(str)

 

"__sub__"와 같이 두개의 밑줄 문자가 앞뒤로 있는 메서드(__NAME__)는 연산자중복을 위하여 미리 정의된 특별한 메서드이다파이썬에서는 이러한 연산자와 정의된 메서드의 이름간에는 미리 맵핑이 되어있다해당 연산자가 클래스에서 사용되는 경우그 맵핑된 메서드가 호출되며 개발자가 정의한 동작을 수행한다.

 

파이썬에서는 기본적으로 제겅되는 연산자 중복정의가 없으므로 개발자가 명시적으로 중복하지 않은 연산자를 사용하는경우 TypeError가 발생한다.

>>> g = gstring('ABCDEFGabcdefg')

>>> g + 'apple'

Traceback (most recent call last):

  File "<pyshell#40>", line 1, in <module>

    g+'apple'

TypeError: unsupported operand type(s) for +: 'gstring' and 'str'

미리 정의된 메서드를 재정의함으로써 프로그래머가 의도한대로 연산자가 동작하도록 하는 방법에 대해서 알아보았다.

이제 연산자중복을 위한 미리 정의된 메서드에 대해 알아보자

 

>수치연산자

수치연산을 위하여 미리 정의된 메서드는 아래와 같다.

메서드

연산자

사용 예

__add__(self,other)

+ (이항)

A + B, A += B

__sub__(self,other)

- (이항)

A - B, A -= B

__mul__(self,other)

*

A * B, A *= B

__truediv__(self,other)

/

A / B, A /= B

(3이상지원그 이하버전은 __div__가 사용됨)

__floordiv__(self,other)

//

A //B, A //= B

__mod__(self,other)

%

A % B, A %= B

__divmod__(self,other)

divmod()

divmod(A,B)

__pow__(self,other[,modulo])

pow(),**

pow(A,B), A ** B

__lshift__(self,other)

<< 

A << B, A <<= B

__rshift__(self,other)

>> 

A >> B, A >>= B

__and__(self,other)

&

A & B, A &= B

__xor__(self,other)

^

A ^ B, A ^= B

__or__(self,other)

|

A | B, A |= B

__abs__(self)

abs()

abs(A)

__pos__(self)

+ (단항)

+ A

__neg__(self)

- (단항)

- A

__invert__(self)

~

~A(비트연산자)

 

아래의 코드는 '-'연산자와 'abs()'내장함수를 중복한 예이다.

class gstring:

    def __init__(self,init=None):

        self.content=init

 

    def __sub__(self,str): #'-'연산자중복

        for i in str:

            self.content=self.content.replace(i,'')

        return gstring(self.content)

 

    def __abs__(self): #'abs()'내장함수중복

        return gstring(self.content.upper())

 

    def Print(self):

        print(self.content)

 

g = gstring('aBcdef')

g -= 'df' #'-'연산자가 중복된경우 '-='도 지원

g.Print() #출력결과: 'aBce'

g = abs(g)

g.Print() #출력결과: 'ABCE'

'-='과 같은 확장연산자가 존재하는 경우기본연산자('-')를 통하여 연산이 가능하기에 중복된 기본연산으로 대치되어 수행된다.

 

위의 경우와 다르게 확장 연산자와 기본연산자의 동작을 구분해야만 하는 경우도 필요할것이다이러한 경우를 위하여 확장연산만을 위한 메서드가 아래와 같이 지원된다.

메서드

연산자

사용 예

__iadd__(self,other)

+=

A += B

__isub__(self,other)

-=

A -= B

__imul__(self,other)

*=

A *= B

__itruediv__(self,other)

/=

A /= B

__ifloordiv__(self,other)

//=

A //= B

__imod__(self,other)

%=

A %= B

__ipow__(self,other)

**=

A **= B

__ilshift__(self,other)

<<=

A <<= B

__irshift__(self,other)

>>=

A >>= B

__iand__(self,other)

&=

A &= B

__ior__(self,other)

|=

A |= B

__ixor__(self,other)

^=

A ^= B

 

아래의 예제와 같이 '-'연산자와 '-='연산자를 각각 중복하여 정의한 경우연산자에 따라 해당메서드가 호출되는것을 알수 있다.

class gstring:

    def __init__(self,init=None):

        self.content=init

 

    def __sub__(self,str): #'-'연산자중복

        print('- operator is called!')

 

    def __isub__(self,str): #'-='연산자중복

        print('-= operator is called!')

 

g = gstring('aBcdef')

g - 'a' #출력결과: '- operator is called!'

g -= 'a' #출력결과: '-= operator is called!'

 

위의 코드에서 피연산자의 순서가 변경되면 다음과 같이 TypeError가 발생한다.

그 이유는 g - 'a'의 경우 __sub__메서드가 호출되지만

'a' - g의 경우 __rsub__메서드가 호출되기 때문이다.

>>> g = gstring('aBcdef')

>>> 'a' - g

Traceback (most recent call last):

  File "<pyshell#42>", line 1, in <module>

    'a' - g

TypeError: unsupported operand type(s) for -: 'str' and 'gstring'

아래의 표는 피연산자의 위치가 바뀐경우에 호출되는 메서드목록이다.

사용예에서 'A'는 연산자중복을 작성한 클래스의 인스턴스객체이다.

메서드

연산자

사용 예

__radd__(self,other)

+

B + A

__rsub__(self,other)

-

B - A

__rmul__(self,other)

*

B * A

__rtruediv__(self,other)

/

B / A

__rfloordiv__(self,other)

//

B // A

__rmod__(self,other)

%

B % A

__rdivmod__(self,other)

divmod()

divmod(B,A)

__rpow__(self,other)

**

B ** A

__rlshift__(self,other)

<< 

B << A

__rrshift__(self,other)

>> 

B >> A

__rand__(self)

&

B & A

__ror__(self)

|

B | A

__rxor__(self)

^

B ^ A

 

그 외 비교연산자와 해당메서드는 아래와 같다.

메서드

연산자

사용 예

__lt__(self,other)

A < B, B < A

--le__(self,other)

<=

A <= B, B <= A

__eq__(self,other)

==

A == B, B == A

__ne__(self,other)

!=

A != B, B != A

__ge__(self,other)

>=

A >= B, B <= A

__gt__(self,other)

A > B, B > A

 

>시퀸스형 연산자

시퀸스객체를 위한 연산자중복정의메서드는 아래와 같다.

메서드

연산자

사용 예

__len__(self)

len()

len(A)

__contain__(self,item)

in

item in A

__getitem__(self,key)

A[key]

A[key], for

__setitem__(self,key,value)

A[key]=value(배정문)

A[key] = value

__delitem__(self,key)

del A[key]

del A[key]

 

 

아래는 사용자로부터 초기값을 받아서 그 범위안에서 인덱스로 전달받은 값의 10배를 반환하는 객체를 생성하는 예이다.

class sequencer:

    def __init__(self,maxValue): #생성자메서드

        self.maxValue=maxValue

 

    def __len__(self): #len()내장함수

        return self.maxValue

 

    def __getitem__(self,index): #인덱스로 아이템의 값을 접근

        if(0 < index <= self.maxValue):

            return (index * 10)

        else:

            raise IndexError('index out of range')

 

    def __contains__(self,item): #불린 형태로 인덱스를 넘어갔는지 반환

        return (0 < item <= self.maxValue)

 

실행

>>> s = sequencer(5) #초기값설정

>>> s[1] #인덱스로접근

10

>>> s[3]

30

>>> [s[i] for i in range(1,6)] #s객체를 통하여 얻을수 있는 값

[10, 20, 30, 40, 50]

>>> len(s) #s객체의 길이

5

>>> 3 in s #포함 유무 확인

True

>>> 7 in s

False

>>> s[7] #초기값 이상의 접근에 대해서는 IndexError발생

Traceback (most recent call last):

  File "<pyshell#53>", line 1, in <module>

    s[7]

  File "D:\Cloude\[Blog]\python.py", line 12, in __getitem__

    raise IndexError('index out of range')

IndexError: index out of range

 

 

참조 : 빠르게 활용하는 파이썬프로그래밍

'Python' 카테고리의 다른 글

Python, 모듈 사용하기  (0) 2016.05.17
Python, 클래스(Class) - 상속  (0) 2016.05.09
Python, 클래스(Class)  (0) 2016.05.09
Python, 정적메소드,클래스메소드  (0) 2016.05.09
Python, @property  (0) 2016.05.09
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함