4-3. Meta Class(3)

uoayopΒ·2021λ…„ 3μ›” 27일
0

Leaf와 Python

λͺ©λ‘ 보기
17/21
post-thumbnail

이전 κ°•μ˜μ—μ„œ 배운 λ‚΄μš©μ„ μ‹€μŠ΅ μœ„μ£Όλ‘œ μ •λ¦¬ν•΄λ³΄μž

Mata Class

  • 였늘의 ν‚€μ›Œλ“œ
    • Type inheritance
      νƒ€μž…μ„ μƒμ†ν•˜λŠ” νƒ€μž…ν΄λž˜μŠ€λŠ” λ°”λ‘œ λ©”νƒ€ν΄λž˜μŠ€λ‹€.
    • Custom Meta Class (였늘의 핡심)
      νƒ€μž…ν΄λž˜μŠ€λ₯Ό 상속 λ°›μœΌλ©΄ 우리만의 μ»€μŠ€ν…€ 메타 클래슀λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.
    • 메타 클래슀 상속 μ‹€μŠ΅

메타 클래슀λ₯Ό μƒμ†ν•œλ‹€λŠ”κ²Œ 무슨 μ˜λ―Έκ°€ μžˆλ‚˜μš”? πŸ€”

➒ 메타 클래슀λ₯Ό μƒμ†ν•œλ‹€λŠ” 것은 type 클래슀λ₯Ό μƒμ†ν•œλ‹€λŠ” 것이닀.

➒ type 클래슀λ₯Ό 상속 λ°›κ³ , 객체가 μΈμŠ€ν„΄μŠ€ν™” λ λ•Œ νƒ€μž…μ˜ λ‚΄λΆ€μ μœΌλ‘œ ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜κ°€ μžˆλ‹€.

이 ν•¨μˆ˜λ₯Ό μ΄μš©ν•΄μ„œ ꡬ쑰적으둜 μ΄ˆκΈ°ν™” λ˜λŠ” μ‹œμ μ— μš°λ¦¬κ°€ μ›ν•˜λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆλ‹€.

➒ 이λ₯Ό μ΄μš©ν•΄μ„œ μ»€μŠ€ν…€ 메타 클래슀λ₯Ό 생성할 수 μžˆλ‹€.

  • 클래슀 생성을 κ°€λ‘œμ±„κΈ° (__new__λ‚˜ __init__ λ“± )
  • 클래슀 μˆ˜μ •ν•˜κΈ° ( modify)
  • 클래슀 κ°œμ„ ν•˜κΈ° (κΈ°λŠ₯ μΆ”κ°€)
  • μˆ˜μ •λœ 클래슀 λ°˜ν™˜ν•˜κΈ°

μ»€μŠ€ν…€ λ©”νƒ€ν΄λž˜μŠ€ 생성 예제 (type ν•¨μˆ˜ 상속 X)

클래슀 λ°”κΉ₯에 μ •μ˜λœ λ©”μ†Œλ“œλ₯Ό κ°€μ Έλ‹€ μ“°λŠ” μ»€μŠ€ν…€ 메타 클래슀λ₯Ό λ§Œλ“œλ €κ³  ν•œλ‹€.
그런데 μ΄λ•Œ λ©”μ†Œλ“œλŠ” selfλ₯Ό μ΄μš©ν•˜κ²Œ λ§Œλ“€μ—ˆλ‹€.
selfλŠ” μΈμŠ€ν„΄μŠ€ μžμ‹ μ„ μ˜λ―Έν•˜λ―€λ‘œ, 즉 selfλŠ” μ‹œν€€μŠ€ν˜• 데이터가 될 것이닀.

def cus_mul(self, d):
    for i in range(len(self)):
        self[i] = self[i] * d


def cus_replace(self, old, new):
    while old in self:
        self[self.index(old)] = new

type ν•¨μˆ˜λ₯Ό μ΄μš©ν•΄μ„œ λ°°μ—΄ μžλ£Œν˜• ; listλ₯Ό μƒμ†λ°›λŠ” 메타 클래슀λ₯Ό λ§Œλ“€μ–΄λ³΄μž.

CustomList1 = type(
    'CustomList1',
    (list,),
    {  
        'desc': 'μ»€μŠ€ν…€ 리슀트1',
        'cus_mul': cus_mul,
        'cus_replace': cus_replace,
    }
)

c1 = CustomList1([1, 2, 4, 5, 3, 3])

μ»€μŠ€ν…€ 메타 클래슀 CustomList1 λŠ” list λ₯Ό 상속 λ°›μ•˜κΈ° λ•Œλ¬Έμ—,
이λ₯Ό μΈμŠ€ν„΄μŠ€ν™” ν• λ•Œ 배열을 인자둜 λ„£μ–΄μ€ŒμœΌλ‘œμ„œ selfλŠ” μš°λ¦¬κ°€ μž…λ ₯ν•œ 배열이 λ˜μ—ˆλ‹€.

c1.cus_mul(1000)
print('ex 1>', c1)
# ex 1> [1000,2000,4000,5000,3000,3000]

# 3000을 haha둜 λ°”κΎΈκ² λ‹€.
c1.cus_replace(3000, 'haha')
print('ex 1>', c1)
# ex 1> [1000,2000,4000,5000,'haha','haha']

print('ex 1>', c1.desc)
# ex 1> μ»€μŠ€ν…€ 리슀트1

print('ex 1>', dir(c1))
# μš°λ¦¬κ°€ μΆ”κ°€ν•œ λ©”μ†Œλ“œμ™€
# λ¦¬μŠ€νŠΈμ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” λ‚΄μž₯ν•¨μˆ˜λ“€μ΄ ν¬ν•¨λ˜μ–΄ μžˆλ‹€.
# ['append', 'sort', ..., 'cus_mul', 'cus_replace', 'desc' ]

μ»€μŠ€ν…€ λ©”νƒ€ν΄λž˜μŠ€ 생성 예제 (type ν•¨μˆ˜ 상속 O)

type ν•¨μˆ˜λ₯Ό 상속 λ°›μ•„ 직접 μ»€μŠ€ν…€ λ©”νƒ€ν΄λž˜μŠ€λ₯Ό λ§Œλ“¦μœΌλ‘œμ„œ,
예제 1λ²ˆμ—μ„œ 보이지 μ•Šμ•˜λ˜ λ‚΄λΆ€ 처리 과정을 λ³Ό 수 μžˆλ‹€.

3가지 ν•¨μˆ˜λ₯Ό μ΄μš©ν•΄μ„œ 쑰금 더 λ””ν…ŒμΌν•˜κ²Œ μ»€μŠ€ν„°λ§ˆμ΄μ¦ˆ ν•  수 있게 λœλ‹€.

type ν•¨μˆ˜λ₯Ό 상속할 λ•Œ ν˜ΈμΆœλ˜λŠ” 3가지 ν•¨μˆ˜

  • new -> init -> call μˆœμ„œλ‘œ ν˜ΈμΆœλœλ‹€.
  • new, call은 return을 ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.
  • __new__
    클래슀 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€. (λ©”λͺ¨λ¦¬ μ΄ˆκΈ°ν™”)
    클래슀 생성 μ‹œμ μ— 인자 4κ°œκ°€ λ„˜μ–΄μ˜€κ²Œ λ§Œλ“ λ‹€.
    • metaclass : λ©”νƒ€ν΄λž˜μŠ€μ˜ 이름
    • name, bases, namespace : type ν•¨μˆ˜μ™€ κ°™λ‹€.
  • __init__
    __new__ μ—μ„œ μƒμ„±λœ μΈμŠ€ν„΄μŠ€λ₯Ό μ΄ˆκΈ°ν™”ν•œλ‹€.
    인자 4κ°œκ°€ λ„˜μ–΄μ˜¨λ‹€.
    • self : μΈμŠ€ν„΄μŠ€μ˜ 이름
    • name, bases, namespace : type ν•¨μˆ˜μ™€ κ°™λ‹€.
  • __call__
    μΈμŠ€ν„΄μŠ€λ₯Ό μ‹€ν–‰ν•œλ‹€.
    인자 3κ°œκ°€ λ„˜μ–΄μ˜¨λ‹€.
    • self : μΈμŠ€ν„΄μŠ€μ˜ 이름
    • *args : μž…λ ₯ 받은 μ—¬λŸ¬κ°œμ˜ 인자λ₯Ό μ ‘κ·Όν•  수 μžˆλ‹€.
    • **kwargs : key=value ν˜•νƒœλ‘œ μž…λ ₯ 받은 인자λ₯Ό λ”•μ…”λ„ˆλ¦¬ ν˜•νƒœλ‘œ μ ‘κ·Όκ°€λŠ₯ν•˜λ‹€.

def cus_mul(self, d):
    for i in range(len(self)):
        self[i] = self[i] * d


def cus_replace(self, old, new):
    while old in self:
        self[self.index(old)] = new

# type을 상속받은 메타 클래슀 CustomListMeta
class CustomListMeta(type):
    def __init__(self, object_or_name, bases, dict):
        print('ex2 > __init__ ->', self, object_or_name, bases, dict)
        super().__init__(object_or_name, bases, dict)

    def __call__(self, *args, **kwargs):
        print('ex2 > __call__ ->', self, *args, **kwargs)
        return super().__call__(*args, **kwargs)

    def __new__(metacls, name, bases, namespace):
        print('ex2 > __new__ ->', metacls, name, bases, namespace)
        namespace['desc'] = 'μ»€μŠ€ν…€ 리슀트 2'
        namespace['cus_mul'] = cus_mul  # μž¬μ‚¬μš©
        namespace['cus_replace'] = cus_replace

        return type.__new__(metacls, name, bases, namespace)
        

CustomList2 = CustomListMeta(
    'CustomList2',
    (list,),
    {}
)

예제 1번과 λ™μΌν•˜κ²Œ λ™μž‘ν•œλ‹€.

c2 = CustomList2([1, 2, 3, 4, 5, 6, 7, 8])
c2.cus_mul(1000)
c2.cus_replace(1000, 7777)

print('ex 2>', c2)
print('ex 2>', c2.desc)

# 상속 확인
print(CustomList2.__mro__)
# μ™Όμͺ½μ΄ 였λ₯Έμͺ½μ„ 상속받은 것
#(<class '__main__.CustomList2'>, <class 'list'>, <class 'object'>)

정리

  • 클래슀 λ°”κΉ₯에 μ •μ˜λœ selfλ₯Ό μ“°λŠ” λ©”μ†Œλ“œλŠ” μ»΄ν¬λ„ŒνŠΈν™” λ˜μ–΄,
    메타 클래슀 λ‚΄λΆ€μ˜ λ©”μ†Œλ“œμ—μ„œ μ‚¬μš©λ  수 μžˆλ‹€.
  • type 을 상속 λ°›κ³ , λ‚΄λΆ€ ν•¨μˆ˜μΈ __new__, __init__, __call__ 을 μ΄μš©ν•΄μ„œ λ©”νƒ€ν΄λž˜μŠ€λ₯Ό 쑰금 더 μ²΄κ³„μ μœΌλ‘œ μ»€μŠ€ν„°λ§ˆμ΄μ¦ˆ ν•  수 μžˆλ‹€.

[좜처]

μΈν”„λŸ° - λͺ¨λ‘λ₯Ό μœ„ν•œ 파이썬 : ν•„μˆ˜ 문법 배우기 Feat. μ˜€ν”ˆμ†ŒμŠ€ νŒ¨ν‚€μ§€ 배포 (Inflearn Original)

profile
slow and steady wins the race 🐒

0개의 λŒ“κΈ€