파이썬 λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”©, μ˜€λ²„λ‘œλ”©

2021. 5. 18. 02:50ㆍBackend/🐍 Python

λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”©

  • μ˜€λ²„λΌμ΄λ”©μ€ λΆ€λͺ¨ 클래슀의 λ©”μ†Œλ“œλ₯Ό, μžμ‹ ν΄λž˜μŠ€μ—μ„œ μž¬μ •μ˜ ν•˜μ—¬ μ‚¬μš©ν•˜λŠ” 것을 μ˜λ―Έν•œλ‹€.
  • 예λ₯Ό λ“€μ–΄ λΆ€λͺ¨ν΄λž˜μŠ€μ—μ„œ add()λΌλŠ” λ©”μ„œλ“œλŠ” 2개의 μΈμžλ°–μ— 더할 수 μ—†μ§€λ§Œ, μžμ‹ 클래슀의 add() λ©”μ†Œλ“œλŠ” μ˜€λ²„λΌμ΄λ”©λ˜μ–΄ 3κ°€μ§€μ˜ μΈμžκΉŒμ§€ 받도둝 μž¬μ •μ˜ ν•  수 μžˆλ‹€.
  1. μ„œλΈŒν΄λž˜μŠ€(μžμ‹)μ—μ„œ 슈퍼(λΆ€λͺ¨)클래슀λ₯Ό 호좜 ν›„ μ‚¬μš©
  2. λ©”μ†Œλ“œ 재 μ •μ˜ ν›„ μ‚¬μš©κ°€λŠ₯
  3. λΆ€λͺ¨ν΄λž˜μŠ€μ˜ λ©”μ†Œλ“œλ₯Ό 좔상화 ν›„ μ‚¬μš©κ°€λŠ₯ (ꡬ쑰적 μ ‘κ·Ό κ°€λŠ₯)
  4. ν™•μž₯ κ°€λŠ₯ + λ‹€ν˜•μ„±(λ‹€μ–‘ν•œ λ°©μ‹μœΌλ‘œ λ™μž‘ -> λΆ€λͺ¨μ—μ„œ λ©”μ†Œλ“œ ν•˜λ‚˜λ₯Ό λ§Œλ“€μ§€λ§Œ,μ‚¬μš©ν•˜λŠ” μžμ‹μ— 따라 λ‹€μ–‘ν•˜κ²Œ μ‚¬μš©λ  수 μžˆλ‹€)
  5. 가독성 증가, 였λ₯˜κ°€λŠ₯μ„± κ°μ†Œ, λ©”μ†Œλ“œ 이름 μ ˆμ•½(λΆ€λͺ¨κ°€ λ©”μ†Œλ“œ 이름을 이미 μ •μ˜ν•΄λ†¨κΈ°μ—)

dir(),_dict_ 객체 λ‚΄λΆ€ 검사 λ©”μ„œλ“œ

  • dir() : ν΄λž˜μŠ€μ™€ μΈμŠ€ν„΄μŠ€ λ‚΄λΆ€μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” 정보λ₯Ό 확인
  • _dict_ : μΈμŠ€ν„΄μŠ€ 내뢀에 μ–΄λ–€ 속성이 μžˆλŠ”μ§€ 확인
    • μžμ‹ ν΄λž˜μŠ€κ°€ λΆ€λͺ¨ν΄λž˜μŠ€λ₯Ό μƒμ†λ°›λŠ”λ‹€ ν•˜λ”λΌλ„, μΈμŠ€ν„΄μŠ€ν™” 되기 μ „μ—” _dict_ 의 κ²°κ³Όκ°€ λ‹€λ₯΄λ‹€. (μΈμŠ€ν„΄μŠ€ν™” μ‹œμ μ— λ‚΄λΆ€ μ†μ„±κΉŒμ§€ 상속)
  • λ‚΄μš©μ΄ μ–΄λ €μš°λ‹ˆ μ½”λ“œλ‘œ ν™•μΈν•΄λ³΄μž
# 기본 Overriding 예제
class ParentEx1():
    def __init__(self):
        self.value = 5

    def get_value(self):
        return self.value


class ChildEx1(ParentEx1):  # ParentEx1 상속 κ°±
    # μ˜€λ²„λΌμ΄λ”©(μž¬μ •μ˜)ν•˜μ§€ μ•Šμ•˜λ‹€.
    pass
# ChildEx1()λŠ” c1 λ³€μˆ˜μ—κ²Œ ν• λ‹Ήν•˜κΈ° μ „κΉŒμ§„, μΈμŠ€ν„΄μŠ€ν™”λœ 것 μ•„λ‹ˆλ‹€.
c1 = ChildEx1() 

# ParentEx1()도 λ§ˆμ°¬κ°€μ§€
p1 = ParentEx1()

print('Ex 1 >', c1.get_value())
>>> 5
# λ©”μ†Œλ“œ μž¬μ •μ˜(μ˜€λ²„λΌμ΄λ”©)κ°€ μ—†μ—ˆκΈ° λ•Œλ¬Έμ— λΆ€λͺ¨ν΄λž˜μŠ€μ—μ„œ μ§€μ •ν•œ 값을 κ·ΈλŒ€λ‘œ 좜λ ₯


# c1의 λͺ¨λ“  속성 좜λ ₯
print(dir(c1))  # get_value, valueλ₯Ό 가지고 μžˆλ‹€.

# λΆ€λͺ¨ & μžμ‹μ˜ λͺ¨λ“  속성값 좜λ ₯
print('Ex 1 > ', dir(ParentEx1))
print('Ex 1 > ', dir(ChildEx1))  
# λ©”μ†Œλ“œκ°€ κ°™λ‹€ -> λΆ€λͺ¨ 클래슀의 get_value() λ©”μ†Œλ“œλ₯Ό μƒμ†λ°›λŠ”λ‹€.

print('Ex 1 >', ParentEx1.__dict__)
print('Ex 1 >', ChildEx1.__dict__)
  • λ”•μ…”λ„ˆλ¦¬λ‘œ λ„€μž„μŠ€νŽ˜μ΄μŠ€λ‚΄μ˜ 속성듀을 ν™•μΈν•˜λŠ”λ°, λΆ€λͺ¨μ—κ²ŒλŠ” μžˆμ§€λ§Œ, μžμ‹μ—κ²ŒλŠ” μ—†λ‹€.
  • μΈμŠ€ν„΄μŠ€κ°€ λ˜λŠ” μ‹œμ μ— μžμ‹μ—κ²Œ λ‹΄κΈ°λŠ” 것이닀(c1=ChildEx1 μ΄λ ‡κ²Œ ν• λ‹Ήν•˜λŠ” 것이 μΈμŠ€ν„΄μŠ€ν™” μ‹œμ , κ·Έλ ‡κΈ° λ•Œλ¬Έμ— dir()κ³Ό __dict__둜 μ°μ„λ•Œ λ‹€λ₯΄κ²Œ λ‚˜μ˜¨λ‹€.

λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”© 예제

  • μ•„λž˜ μ˜ˆμ œμ—μ„  λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”©μ΄ μΌμ–΄λ‚˜, get_valueλΌλŠ” λ©”μ†Œλ“œμ—μ„œ κΈ°μ‘΄ self.value에 10을 κ³±ν•˜μ—¬ λ¦¬ν„΄ν•˜κ²Œ λœλ‹€.
class ParentEx2():
    def __init__(self):
        self.value = 5

    def get_value(self):
        return self.value


class ChildEx2(ParentEx2):
    def get_value(self):  # λ©”μ†Œλ“œ λ³€κ²½ => λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”©
        return self.value * 10


c2 = ChildEx2()
print("Ex 2 >", c2.get_value())

# Ex1 κ³Ό 달리 Ex2에선 λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”©μ΄ 일어났기 λ•Œλ¬Έμ—, 5κ°€ μ•„λ‹Œ 50이 좜λ ₯λœλ‹€.

λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”© λ‹€ν˜•μ„± 예제

import datetime

# λΆ€λͺ¨ 클래슀
class Logger():
    def log(self, msg):
        print(msg)

# Logger의 TimestampLoggerλΌλŠ” μžμ‹ (μžμ‹1)
class TimestampLogger(Logger):
    def log(self, msg):
        message = '{ts} {msg}'.format(ts=datetime.datetime.now(), msg=msg)
        super().log(message) # λΆ€λͺ¨ν΄λž˜μŠ€μ˜ log() λ©”μ†Œλ“œλ‘œ message인자λ₯Ό λ„˜κ²¨λ²Œμž„
        # super(TimestampLogger, self).log(message) # μœ„ μ½”λ“œμ™€ λ‹€λ₯Ό λ°” μ—†μ§€λ§Œ 더 λͺ…ν™•ν•˜λ‹€, # fm style 둜 μ½”λ”©ν•œ 것


# Logger의 DateLoggerλΌλŠ” μžμ‹ (μžμ‹2) ==> μ—¬λŸ¬ μžμ‹ 생김 : λ‹€ν˜•μ„±
class DateLogger(Logger):
    def log(self, msg):
        message = "{ts} {msg}".format(ts=datetime.datetime.now().strftime('%Y-%m-%d'), msg=msg)
        super().log(message)

λ‹€ν˜•μ„±

ν•˜λ‚˜μ˜ λΆ€λͺ¨(Logger 클래슀)λ₯Ό μ •ν•˜κ³ ,
λ‹€μ–‘ν•œ ν˜•νƒœ(TimestampLogger, DateLogger 클래슀)둜 상속을 λ°›λŠ”λ‹€.

# λΌˆλŒ€λŠ” λΆ€λͺ¨κ°€ 제곡 <좜λ ₯ κΈ°λŠ₯ print(msg)> => 좜λ ₯ν•  λ©”μ„Έμ§€μ˜ ν˜•νƒœλŠ” μžμ‹μ΄ κ²°μ •
l = Logger()
t = TimestampLogger()
d = DateLogger()
# μΈμŠ€ν„΄μŠ€ μƒμ„±λ˜λ©΄μ„œ, λΆ€λͺ¨ν΄λž˜μŠ€μ˜ 속성 상속 μ™„λ£Œ


l.log('test1')
t.log('test2')
d.log('test3')

>>> test1
>>> 2021-04-06 21:12:30.730855 test2
>>> 2021-04-06 test3

λΆ„λͺ… ν•˜λ‚˜μ˜ λΆ€λͺ¨ν΄λž˜μŠ€μ—μ„œ log() λ©”μ†Œλ“œλ₯Ό μƒμ†λ°›μ•˜μ§€λ§Œ, μžμ‹ ν΄λž˜μŠ€μ—μ„  λ‹€μ–‘ν•œ ν˜•νƒœλ‘œ 좜λ ₯됨을 확인 ν•  수 μžˆλ‹€. 이렇듯 λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”©μ„ 톡해 λ‹€ν˜•μ„± κ΅¬ν˜„μ΄ κ°€λŠ₯ν•˜λ‹€.



파이썬 λ©”μ†Œλ“œ μ˜€λ²„λ‘œλ”©

  • 동일 클래슀 λ‚΄μ—μ„œ, λ§€κ°œλ³€μˆ˜μ˜ 개수 λ˜λŠ” μžλ£Œν˜•(int, float λ“±)이 λ‹€λ₯Έ 동λͺ…μ˜ λ©”μ†Œλ“œλ₯Ό μ •μ˜ν•˜λŠ” 것.
    즉, 클래슀 λ‚΄μ—μ„œ 같은 μ΄λ¦„μ˜ λ©”μ†Œλ“œλ₯Ό μ—¬λŸ¬ 개 μ„ μ–Έν•˜λŠ” 것을 μ˜λ―Έν•œλ‹€.
  • Q. μ™œ 이런 것을 λ§Œλ“œλŠλƒ?.!
  • A. λ‹€μ–‘ν•œ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„ μ²˜λ¦¬ν•  수 μžˆλ„λ‘ ν•˜κΈ° μœ„ν•¨μ΄λ‹€.
    ex) λ”ν•˜κΈ° λ©”μ†Œλ“œλ₯Ό λ§Œλ“€ λ•Œ, λ‘κ°œμ˜ λ§€κ°œλ³€μˆ˜λ§Œ λ°›λŠ” λ©”μ†Œλ“œμ™€, μ„Έκ°œμ˜ λ§€κ°œλ³€μˆ˜, ν˜Ήμ€ κ·Έ 이상 개수의 λ§€κ°œλ³€μˆ˜λ₯Ό 받을 수 μžˆλŠ” λ”ν•˜κΈ° λ©”μ†Œλ“œλ₯Ό λ§Œλ“€ 수 μžˆλ‹€ (λ™μΌν•œ λ©”μ†Œλ“œ μ΄λ¦„μœΌλ‘œ)

Ex 1

  • 동일 이름 λ©”μ†Œλ“œ μ‚¬μš© 예제
  • 동적 νƒ€μž… 검사 -> μ‹€ν–‰ μ‹œ νƒ€μž… 검사(νƒ€μž… μ—λŸ¬κ°€ μ‹€ν–‰μ‹œμ— 발견) -> κΈ°μˆ λ©΄μ ‘μ—μ„œ 많이 λ¬Όμ–΄λ³Έλ‹€.
class SampleA():
    def add(self, x, y):
        return x + y

    def add(self, x, y, z):
        return x + y + z

    # def add(self, *args): # 인자λ₯Ό μ–ΈνŒ©ν‚Ήν•˜μ—¬ μΈμžκ°€ λͺ‡κ°œλ“  상관없이 μ‚¬μš©ν•  수 μžˆλ‹€.
    #     return sum(args)

a = SampleA()

μ΄λ ‡κ²Œ 동일 λ„€μ΄λ°μœΌλ‘œ μ„œλ‘œ λ‹€λ₯Έ 개수의 λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ§€λ§Œ, μ•„λž˜μ—μ„œ 보면 (Java와 달리) λ°”λ‘œ μ—λŸ¬ 터진닀.

print('Ex 1 > ', a.add(2, 3)) 
>>> TypeError: add() missing 1 required positional argument: 'z'

# λ°”λ‘œ μ—λŸ¬ν„°μ§„λ‹€ => 동일 λ©”μ„œλ“œλͺ…이기에, μΈμžκ°€ μ„Έκ°œλ₯Ό λ°›λŠ” add()κ°€ ν˜ΈμΆœλœλ‹€.
  • νŒŒμ΄μ¬μ—μ„œλŠ” λ©”μ†Œλ“œ μ˜€λ²„λ‘œλ”©μ„ μ§€μ›ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— λ°œμƒν•˜λŠ” μ—λŸ¬
  • μžλ°”μ—μ„œλŠ” μ˜€λ²„λ‘œλ”© κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ—, λ™μΌν•œ λ„€μž„μ΄λ©΄μ„œ μ—¬λŸ¬κ°œ λ§Œλ“€μ–΄ μ„œλ‘œ λ‹€λ₯Έ 인자 갯수λ₯Ό λ°›λŠ” λ©”μ„œλ“œλ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

Ex 2

  • 동일 이름 λ©”μ†Œλ“œ μ‚¬μš© 예제
  • μžλ£Œν˜•μ— λ”°λ₯Έ λΆ„κΈ° 처리
class SampleB():
    def add(self, datatype, *args):
        if datatype == 'int':
            return sum(args)
        if datatype == 'str':
            return ''.join([x for x in args])

b = SampleB()
# Number
print('Ex 2 > ', b.add('int', 5, 6, 3))
print('Ex 2 > ', b.add('str', 'Hello', 'World'))

Ex3

  • MultipleDispatch νŒ¨ν‚€μ§€λ₯Ό ν†΅ν•œ λ©”μ†Œλ“œ μ˜€λ²„λ‘œλ”© ➑️ pip install multipledispatch ➑️ λ©”μ†Œλ“œμ— @dispatch μ–΄λ…Έν…Œμ΄μ…˜μ„ λΆ™μ—¬ 적용 ➑️ 이제 μžλ°”μ—μ„œ 처럼 μ˜€λ²„λ‘œλ”© κ°€λŠ₯
from multipledispatch import dispatch
class SampleC():
    @dispatch(int, int)
    def product(self, x, y):
        return x * y

    @dispatch(int, int, int)
    def product(self, x, y, z):
        return x * y * z

    @dispatch(float, float, float)
    def product(self, x, y, z):
        return x * y * z

c = SampleC()

# νŒŒλΌλ―Έν„° 2개
print("Ex 3 > ", c.product(3, 4))
>>> Ex 3 >  12

# νŒŒλΌλ―Έν„° 3개
print("Ex 3 > ", c.product(3, 4, 5))
>>> Ex 3 >  60

# νŒŒλΌλ―Έν„° 3개 μžλ£Œν˜• float
print("Ex 3 > ", c.product(3.5, 4.0, 1.2))
>>> Ex 3 >  16.8
  • 각 상황에 맞게 dispatch, μ˜€λ²„λ‘œλ”©λ˜μ–΄ λ©”μ†Œλ“œ 호좜
  • Ex2와 λ‹€λ₯΄κ²Œ 일일이 데이터 νƒ€μž…μ„ λͺ…μ‹œν•  ν•„μš”μ—†μ΄, @dispatch μ–΄λ…Έν…Œμ΄μ…˜ 덕뢄에 μžλ™μœΌλ‘œ μ²˜λ¦¬λœλ‹€.
  • 데이터 νƒ€μž…μ˜ κ΄€μ μ—μ„œ λ©”μ†Œλ“œλ₯Ό μž‘μ„±ν•˜μ—¬ ꡬ쑰성 μžˆλŠ” 클래슀 생성