KR_MagicMethod - somaz94/python-study GitHub Wiki

Python 맀직 λ©”μ„œλ“œ κ°œλ… 정리


1️⃣ κΈ°λ³Έ 맀직 λ©”μ„œλ“œ

객체의 κΈ°λ³Έ λ™μž‘μ„ μ •μ˜ν•˜λŠ” νŠΉλ³„ν•œ λ©”μ„œλ“œλ“€μ΄λ‹€.

class Number:
    def __init__(self, value):  # μ΄ˆκΈ°ν™”
        self.value = value
    
    def __str__(self):         # λ¬Έμžμ—΄ ν‘œν˜„
        return f"Number({self.value})"
    
    def __repr__(self):        # 개발자λ₯Ό μœ„ν•œ λ¬Έμžμ—΄ ν‘œν˜„
        return f"Number({self.value})"
    
    def __bool__(self):        # bool() ν•¨μˆ˜λ‚˜ μ‘°κ±΄λ¬Έμ—μ„œ 평가
        return self.value != 0
    
    def __hash__(self):        # ν•΄μ‹œκ°’ λ°˜ν™˜ (λ”•μ…”λ„ˆλ¦¬ ν‚€λ‘œ μ‚¬μš© κ°€λŠ₯)
        return hash(self.value)
    
    def __format__(self, format_spec):  # format() ν•¨μˆ˜ 및 f-λ¬Έμžμ—΄μ—μ„œ μ‚¬μš©
        if format_spec == 'hex':
            return f"0x{self.value:x}"
        return str(self)

num = Number(42)
print(str(num))       # Number(42)
print(repr(num))      # Number(42)
print(bool(num))      # True
print(bool(Number(0))) # False
print(f"{num:hex}")   # 0x2a

# ν•΄μ‹œν…Œμ΄λΈ”(λ”•μ…”λ„ˆλ¦¬) ν‚€λ‘œ μ‚¬μš©
d = {num: "answer"}
print(d[num])         # answer

βœ… νŠΉμ§•:

  • 객체 μ΄ˆκΈ°ν™”
  • λ¬Έμžμ—΄ λ³€ν™˜
  • 디버깅 ν‘œν˜„
  • 진리값 평가
  • ν•΄μ‹œ κ°€λŠ₯ 객체
  • ν˜•μ‹ν™” μ œμ–΄


2️⃣ μ—°μ‚°μž μ˜€λ²„λ‘œλ”©

Python의 μ—°μ‚°μž λ™μž‘μ„ μ‚¬μš©μž μ •μ˜ ν΄λž˜μŠ€μ— 맞게 μž¬μ •μ˜ν•  수 μžˆλ‹€.

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):      # + μ—°μ‚°μž
        return Vector(self.x + other.x, self.y + other.y)
    
    def __sub__(self, other):      # - μ—°μ‚°μž
        return Vector(self.x - other.x, self.y - other.y)
    
    def __mul__(self, scalar):     # * μ—°μ‚°μž (Vector * scalar)
        return Vector(self.x * scalar, self.y * scalar)
    
    def __rmul__(self, scalar):    # * μ—°μ‚°μž (scalar * Vector)
        return self.__mul__(scalar)
    
    def __truediv__(self, scalar): # / μ—°μ‚°μž
        return Vector(self.x / scalar, self.y / scalar)
    
    def __eq__(self, other):       # == μ—°μ‚°μž
        return self.x == other.x and self.y == other.y
    
    def __lt__(self, other):       # < μ—°μ‚°μž
        return (self.x**2 + self.y**2) < (other.x**2 + other.y**2)
    
    def __abs__(self):             # abs() ν•¨μˆ˜
        return (self.x**2 + self.y**2) ** 0.5
    
    def __neg__(self):             # -벑터 (λΆ€ν˜Έ λ°˜μ „)
        return Vector(-self.x, -self.y)
    
    def __str__(self):
        return f"Vector({self.x}, {self.y})"

# μ—°μ‚°μž μ‚¬μš© μ˜ˆμ‹œ
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2           # Vector(4, 6)
v4 = v1 * 2            # Vector(2, 4)
v5 = 3 * v1            # Vector(3, 6) - __rmul__ 덕뢄에 κ°€λŠ₯
v6 = v2 / 2            # Vector(1.5, 2.0)
print(abs(v1))         # 2.23606... (λ²‘ν„°μ˜ 크기)
print(v1 < v2)         # True (v1의 크기 < v2의 크기)
print(-v1)             # Vector(-1, -2)

βœ… νŠΉμ§•:

  • μ‚°μˆ  μ—°μ‚°μž (add, sub, mul, truediv, λ“±)
  • μ—­λ°©ν–₯ μ—°μ‚°μž (radd, rsub, rmul, λ“±)
  • 볡합 ν• λ‹Ή μ—°μ‚°μž (iadd, isub, λ“±)
  • 비ꡐ μ—°μ‚°μž (eq, ne, lt, gt, λ“±)
  • 단항 μ—°μ‚°μž (pos, neg, abs, λ“±)
  • 직관적인 객체 μ—°μ‚° κ΅¬ν˜„
  • μ—°μ‚°μž μš°μ„ μˆœμœ„ μœ μ§€


3️⃣ μ»¨ν…Œμ΄λ„ˆ λ™μž‘ μ •μ˜

λ¦¬μŠ€νŠΈλ‚˜ λ”•μ…”λ„ˆλ¦¬ 같은 μ»¨ν…Œμ΄λ„ˆμ²˜λŸΌ λ™μž‘ν•˜λŠ” μ‚¬μš©μž μ •μ˜ 클래슀λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

class MyList:
    def __init__(self, items):
        self.items = items
    
    def __len__(self):            # len() ν•¨μˆ˜
        return len(self.items)
    
    def __getitem__(self, index): # 인덱싱 및 μŠ¬λΌμ΄μ‹±
        return self.items[index]
    
    def __setitem__(self, index, value): # ν•­λͺ© μ„€μ •
        self.items[index] = value
    
    def __delitem__(self, index): # del μ—°μ‚°μž
        del self.items[index]
    
    def __contains__(self, item): # in μ—°μ‚°μž
        return item in self.items
    
    def __iter__(self):           # forλ¬Έμ—μ„œ 반볡
        return iter(self.items)
    
    def __reversed__(self):       # reversed() ν•¨μˆ˜
        return reversed(self.items)

# μ»¨ν…Œμ΄λ„ˆ λ™μž‘ μ‚¬μš© μ˜ˆμ‹œ
lst = MyList([1, 2, 3, 4, 5])
print(len(lst))        # 5
print(lst[0])          # 1
print(lst[1:3])        # [2, 3] - μŠ¬λΌμ΄μ‹± 지원
lst[0] = 10            # ν•­λͺ© μ„€μ •
print(lst[0])          # 10
print(3 in lst)        # True
del lst[0]             # 첫 번째 ν•­λͺ© μ‚­μ œ
print(lst[0])          # 2

# 반볡 κ°€λŠ₯
for item in lst:
    print(item, end=' ')  # 2 3 4 5

# μ—­μˆœ 반볡
print()
for item in reversed(lst):
    print(item, end=' ')  # 5 4 3 2

# λ”•μ…”λ„ˆλ¦¬ μŠ€νƒ€μΌ μ»¨ν…Œμ΄λ„ˆ
class SimpleDict:
    def __init__(self):
        self._data = {}
    
    def __getitem__(self, key):
        return self._data[key]
    
    def __setitem__(self, key, value):
        self._data[key] = value
    
    def __delitem__(self, key):
        del self._data[key]
    
    def __contains__(self, key):
        return key in self._data
    
    def __iter__(self):
        return iter(self._data)

d = SimpleDict()
d['name'] = '홍길동'
print(d['name'])       # 홍길동

βœ… νŠΉμ§•:

  • μ‹œν€€μŠ€/λ§€ν•‘ λ™μž‘ κ΅¬ν˜„
  • 인덱싱/μŠ¬λΌμ΄μ‹± 지원
  • ν•­λͺ© μˆ˜μ • 및 μ‚­μ œ
  • 멀버십 ν…ŒμŠ€νŠΈ (in μ—°μ‚°μž)
  • 반볡 κ°€λŠ₯(iterable) 객체
  • 리슀트/νŠœν”Œ/λ”•μ…”λ„ˆλ¦¬ μœ μ‚¬ λ™μž‘
  • μ‹œν€€μŠ€ ν”„λ‘œν† μ½œ μ€€μˆ˜


4️⃣ 객체 생λͺ…μ£ΌκΈ° κ΄€λ ¨

객체의 생성, μ‚¬μš©, μ†Œλ©Έ μ£ΌκΈ°λ₯Ό κ΄€λ¦¬ν•˜λŠ” 맀직 λ©”μ„œλ“œλ“€μ΄λ‹€.

class Resource:
    def __init__(self, name):
        self.name = name
        print(f"{self.name} λ¦¬μ†ŒμŠ€ μ΄ˆκΈ°ν™”")
    
    def __del__(self):           # μ†Œλ©Έμž
        print(f"{self.name} λ¦¬μ†ŒμŠ€ 정리")
    
    def __enter__(self):         # with λ¬Έ μ‹œμž‘
        print(f"{self.name} μ»¨ν…μŠ€νŠΈ μ‹œμž‘")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb): # with λ¬Έ μ’…λ£Œ
        print(f"{self.name} μ»¨ν…μŠ€νŠΈ μ’…λ£Œ")
        if exc_type is not None:
            print(f"μ˜ˆμ™Έ λ°œμƒ: {exc_val}")
        return False  # Falseλ©΄ μ˜ˆμ™Έ μ „νŒŒ, Trueλ©΄ μ˜ˆμ™Έ μ–΅μ œ

# 일반 μ‚¬μš©
r = Resource("일반")
del r  # λͺ…μ‹œμ  μ†Œλ©Έ

# with λ¬Έ μ‚¬μš© (정상)
with Resource("정상") as r:
    print("λ¦¬μ†ŒμŠ€ μ‚¬μš© 쀑")

# with λ¬Έ μ‚¬μš© (μ˜ˆμ™Έ λ°œμƒ)
try:
    with Resource("μ˜ˆμ™Έ") as r:
        print("λ¦¬μ†ŒμŠ€ μ‚¬μš© 쀑")
        raise ValueError("μ˜ˆμ™Έ ν…ŒμŠ€νŠΈ")
except ValueError:
    print("μ˜ˆμ™Έ 처리됨")

# μƒˆ μŠ€νƒ€μΌ μ»¨ν…μŠ€νŠΈ κ΄€λ¦¬μž (Python 3.10+)
from contextlib import contextmanager

class ModernResource:
    def __init__(self, name):
        self.name = name
    
    @contextmanager
    def session(self):
        print(f"{self.name} μ„Έμ…˜ μ‹œμž‘")
        try:
            yield self
            print(f"{self.name} μ„Έμ…˜ 정상 μ’…λ£Œ")
        except Exception as e:
            print(f"{self.name} μ„Έμ…˜ μ˜ˆμ™Έ μ’…λ£Œ: {e}")
            raise

mr = ModernResource("ν˜„λŒ€μ‹")
with mr.session() as session:
    print("μ„Έμ…˜ μ‚¬μš© 쀑")

βœ… νŠΉμ§•:

  • 객체 μ΄ˆκΈ°ν™” (init)
  • 객체 μ†Œλ©Έ 처리 (del)
  • μ»¨ν…μŠ€νŠΈ κ΄€λ¦¬μž ν”„λ‘œν† μ½œ (enter, exit)
  • λ¦¬μ†ŒμŠ€ 관리 μžλ™ν™”
  • μ˜ˆμ™Έ 처리 및 정리
  • with λ¬Έ ν™œμš©
  • μ•ˆμ „ν•œ λ¦¬μ†ŒμŠ€ ν•΄μ œ 보μž₯


5️⃣ 속성 μ ‘κ·Ό μ œμ–΄

객체의 속성 접근을 μ œμ–΄ν•˜κ³  μ»€μŠ€ν„°λ§ˆμ΄μ§•ν•  수 μžˆλ‹€.

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age
        self._protected = {}
    
    def __getattr__(self, name):  # μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 속성 μ ‘κ·Ό
        return f"{name}은 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” μ†μ„±μž…λ‹ˆλ‹€."
    
    def __getattribute__(self, name):  # λͺ¨λ“  속성 μ ‘κ·Ό
        if name.startswith('_secret_'):
            raise AttributeError(f"{name}은 μ ‘κ·Όν•  수 μ—†μŠ΅λ‹ˆλ‹€.")
        # λ¬΄ν•œ μž¬κ·€ λ°©μ§€λ₯Ό μœ„ν•΄ super() μ‚¬μš©
        return super().__getattribute__(name)
    
    def __setattr__(self, name, value):  # 속성 μ„€μ •
        if name == 'age' and value < 0:
            raise ValueError("λ‚˜μ΄λŠ” μŒμˆ˜κ°€ 될 수 μ—†μŠ΅λ‹ˆλ‹€.")
        print(f"{name} 속성을 {value}둜 μ„€μ •")
        super().__setattr__(name, value)
    
    def __delattr__(self, name):  # 속성 μ‚­μ œ
        if name == '_name':
            raise AttributeError("이름은 μ‚­μ œν•  수 μ—†μŠ΅λ‹ˆλ‹€.")
        print(f"{name} 속성 μ‚­μ œ")
        super().__delattr__(name)
    
    # ν”„λ‘œνΌν‹° μŠ€νƒ€μΌ μ ‘κ·Ό
    @property
    def name(self):
        return self._name
    
    @property
    def age(self):
        return self._age
    
    @age.setter
    def age(self, value):
        if value < 0:
            raise ValueError("λ‚˜μ΄λŠ” μŒμˆ˜κ°€ 될 수 μ—†μŠ΅λ‹ˆλ‹€.")
        self._age = value
    
    # 동적 속성 지원
    def __getitem__(self, key):
        return self._protected.get(key, None)
    
    def __setitem__(self, key, value):
        self._protected[key] = value

# 속성 μ ‘κ·Ό μ˜ˆμ‹œ
p = Person("홍길동", 30)
print(p.name)         # 홍길동
p.age = 35            # age 속성을 35둜 μ„€μ •
print(p.age)          # 35

try:
    p.age = -5        # ValueError: λ‚˜μ΄λŠ” μŒμˆ˜κ°€ 될 수 μ—†μŠ΅λ‹ˆλ‹€.
except ValueError as e:
    print(e)

print(p.address)      # address은 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” μ†μ„±μž…λ‹ˆλ‹€.

try:
    print(p._secret_data)  # AttributeError
except AttributeError as e:
    print(e)

# λ”•μ…”λ„ˆλ¦¬ μŠ€νƒ€μΌ μ•‘μ„ΈμŠ€
p['location'] = 'μ„œμšΈ'
print(p['location'])  # μ„œμšΈ

βœ… νŠΉμ§•:

  • 속성 μ ‘κ·Ό μ œμ–΄
  • 속성 쑴재 μ—¬λΆ€ 확인
  • 동적 속성 처리
  • μ ‘κ·Ό μ œν•œ 및 μœ νš¨μ„± 검증
  • ν”„λ‘œνΌν‹° μŠ€νƒ€μΌ μ•‘μ„ΈμŠ€
  • λ”•μ…”λ„ˆλ¦¬ μŠ€νƒ€μΌ μ•‘μ„ΈμŠ€
  • λ‚΄λΆ€ 속성 보호


6️⃣ 호좜 κ°€λŠ₯ 객체와 μ„€λͺ…μž

ν•¨μˆ˜μ²˜λŸΌ ν˜ΈμΆœν•  수 μžˆλŠ” 객체와 속성 접근을 μ‚¬μš©μžν™”ν•˜λŠ” μ„€λͺ…μž νŒ¨ν„΄μ΄λ‹€.

# 호좜 κ°€λŠ₯ 객체 (Callable)
class Adder:
    def __init__(self, n):
        self.n = n
    
    def __call__(self, x):  # 객체λ₯Ό ν•¨μˆ˜μ²˜λŸΌ 호좜
        return self.n + x

add5 = Adder(5)
print(add5(10))       # 15 - 객체λ₯Ό ν•¨μˆ˜μ²˜λŸΌ 호좜
print(callable(add5))  # True

# μ„€λͺ…μž (Descriptor)
class Validator:
    def __init__(self, min_value=None, max_value=None):
        self.min_value = min_value
        self.max_value = max_value
        self.name = None
    
    def __set_name__(self, owner, name):  # Python 3.6+
        self.name = name
    
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__[self.name]
    
    def __set__(self, instance, value):
        if self.min_value is not None and value < self.min_value:
            raise ValueError(f"{self.name}은(λŠ”) {self.min_value} 이상이어야 ν•©λ‹ˆλ‹€.")
        if self.max_value is not None and value > self.max_value:
            raise ValueError(f"{self.name}은(λŠ”) {self.max_value} μ΄ν•˜μ—¬μ•Ό ν•©λ‹ˆλ‹€.")
        instance.__dict__[self.name] = value

class Person:
    age = Validator(min_value=0, max_value=150)
    height = Validator(min_value=0)
    
    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height

# μ„€λͺ…μž μ‚¬μš© μ˜ˆμ‹œ
p = Person("홍길동", 30, 175)
print(p.age)      # 30

try:
    p.age = -5    # ValueError
except ValueError as e:
    print(e)

try:
    p.age = 200   # ValueError
except ValueError as e:
    print(e)

# ν•¨μˆ˜ μž₯μ‹μžμ™€ 맀직 λ©”μ„œλ“œ κ²°ν•©
def debug_calls(cls):
    original_methods = {}
    
    # λͺ¨λ“  맀직 λ©”μ„œλ“œ μ°ΎκΈ°
    for name, method in vars(cls).items():
        if callable(method) and name.startswith('__') and name.endswith('__'):
            original_methods[name] = method
    
    # 맀직 λ©”μ„œλ“œ λž˜ν•‘
    def wrap_method(name, method):
        def wrapper(self, *args, **kwargs):
            print(f"호좜: {cls.__name__}.{name}({args}, {kwargs})")
            result = method(self, *args, **kwargs)
            print(f"κ²°κ³Ό: {result}")
            return result
        return wrapper
    
    # λž˜ν•‘λœ λ©”μ„œλ“œλ‘œ ꡐ체
    for name, method in original_methods.items():
        setattr(cls, name, wrap_method(name, method))
    
    return cls

@debug_calls
class DebuggableVector(Vector):
    pass

# 디버깅 래퍼 ν…ŒμŠ€νŠΈ
dv1 = DebuggableVector(1, 2)
dv2 = DebuggableVector(3, 4)
result = dv1 + dv2  # 호좜 및 κ²°κ³Ό λ‘œκΉ…μ΄ 좜λ ₯됨

βœ… νŠΉμ§•:

  • 호좜 κ°€λŠ₯ 객체 (call)
  • ν•¨μˆ˜ν˜• 객체 κ΅¬ν˜„
  • μ„€λͺ…μž ν”„λ‘œν† μ½œ (get, set, delete)
  • 속성 μ ‘κ·Ό μ‚¬μš©μžν™”
  • 속성 μœ νš¨μ„± 검사
  • μž¬μ‚¬μš© κ°€λŠ₯ν•œ 속성 둜직
  • 데이터 μΊ‘μŠν™”
  • λ©”νƒ€ν”„λ‘œκ·Έλž˜λ° 기법


7️⃣ κ³ κΈ‰ 맀직 λ©”μ„œλ“œ

덜 자주 μ‚¬μš©λ˜μ§€λ§Œ κ°•λ ₯ν•œ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” 맀직 λ©”μ„œλ“œλ“€μ΄λ‹€.

# 피클링 지원
import pickle

class PickleableClass:
    def __init__(self, value):
        self.value = value
        self._cache = {}  # ν”Όν΄λ§λ˜μ§€ μ•Šμ„ μΊμ‹œ
    
    def __getstate__(self):  # 피클링 μ‹œ 호좜
        # _cacheλŠ” μ œμ™Έν•˜κ³  피클링
        state = self.__dict__.copy()
        del state['_cache']
        return state
    
    def __setstate__(self, state):  # 언피클링 μ‹œ 호좜
        self.__dict__ = state
        self._cache = {}  # μΊμ‹œ μ΄ˆκΈ°ν™”

obj = PickleableClass(42)
obj._cache['temp'] = 'temporary data'

# 피클링 및 언피클링
serialized = pickle.dumps(obj)
deserialized = pickle.loads(serialized)

print(deserialized.value)       # 42
print(hasattr(deserialized, '_cache'))  # True
print(deserialized._cache)      # {} (λΉ„μ–΄μžˆμŒ)

# μ‚¬μš©μž μ •μ˜ 숫자 νƒ€μž…
class Fraction:
    def __init__(self, numerator, denominator):
        self.numerator = numerator
        self.denominator = denominator
        self._simplify()
    
    def _simplify(self):
        # μ΅œλŒ€κ³΅μ•½μˆ˜ 계산
        def gcd(a, b):
            while b:
                a, b = b, a % b
            return a
        
        g = gcd(abs(self.numerator), abs(self.denominator))
        self.numerator //= g
        self.denominator //= g
    
    def __int__(self):  # int() λ³€ν™˜
        return self.numerator // self.denominator
    
    def __float__(self):  # float() λ³€ν™˜
        return self.numerator / self.denominator
    
    def __round__(self, ndigits=0):  # round() ν•¨μˆ˜
        return round(float(self), ndigits)
    
    def __complex__(self):  # complex() λ³€ν™˜
        return complex(float(self), 0)
    
    def __str__(self):
        return f"{self.numerator}/{self.denominator}"

frac = Fraction(22, 7)  # 파이의 근사값
print(str(frac))        # 22/7
print(int(frac))        # 3
print(float(frac))      # 3.142857...
print(round(frac, 2))   # 3.14
print(complex(frac))    # (3.142857...+0j)

# __slots__ μ‚¬μš©μœΌλ‘œ λ©”λͺ¨λ¦¬ μ΅œμ ν™”
class Point:
    __slots__ = ('x', 'y')  # ν—ˆμš©λœ 속성 μ œν•œ
    
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(3, 4)
p.x = 5  # 정상 μž‘λ™
try:
    p.z = 10  # AttributeError: 'Point' object has no attribute 'z'
except AttributeError as e:
    print(e)

βœ… νŠΉμ§•:

  • 객체 직렬화 (getstate, setstate)
  • νƒ€μž… λ³€ν™˜ λ©”μ„œλ“œ (int, float, complex, λ“±)
  • λ©”λͺ¨λ¦¬ μ΅œμ ν™” (slots)
  • 수치 μ—°μ‚° 지원
  • 객체 λΆ„λ₯˜ 및 등둝
  • ν•˜μœ„ 클래슀 확인
  • λ©”νƒ€ν΄λž˜μŠ€ ν”„λ‘œν† μ½œ
  • μ‚¬μš©μž μ •μ˜ μ»¨ν…Œμ΄λ„ˆ λ™μž‘


μ£Όμš” 팁

βœ… λͺ¨λ²” 사둀:

  • __init__κ³Ό __str__ κΈ°λ³Έ κ΅¬ν˜„ν•˜κΈ°
  • __repr__은 κ°€λŠ₯ν•˜λ©΄ 객체 μž¬μƒμ„± μ½”λ“œ λ°˜ν™˜
  • μ—°μ‚°μž μ˜€λ²„λ‘œλ”©μ€ 직관적이고 μΌκ΄€λ˜κ²Œ κ΅¬ν˜„
  • μ»¨ν…Œμ΄λ„ˆ νƒ€μž…μ€ __len__κ³Ό __getitem__ κ΅¬ν˜„
  • λ¦¬μ†ŒμŠ€ κ΄€λ¦¬λŠ” __enter__와 __exit__ μ‚¬μš©
  • 속성 μ ‘κ·Ό μ œμ–΄λŠ” μ‹ μ€‘ν•˜κ²Œ 섀계
  • __eq__λ₯Ό κ΅¬ν˜„ν•  λ•Œ __hash__도 ν•¨κ»˜ κ΅¬ν˜„
  • λ©”λͺ¨λ¦¬ 및 μ„±λŠ₯ μ΅œμ ν™”λ₯Ό μœ„ν•΄ __slots__ μ‚¬μš© κ³ λ €
  • 일관성 μžˆλŠ” λ™μž‘ μœ μ§€ν•˜κΈ°
  • ν‘œμ€€ 라이브러리 κ·œμ•½ λ”°λ₯΄κΈ°
  • 맀직 λ©”μ„œλ“œ 호좜 μ‹œ λ‚΄μž₯ ν•¨μˆ˜ μ‚¬μš©ν•˜κΈ° (직접 호좜 ν”Όν•˜κΈ°)
  • μ„€λͺ…μžμ™€ ν”„λ‘œνΌν‹° ν™œμš©ν•˜μ—¬ 속성 둜직 μž¬μ‚¬μš©
  • 였λ₯˜ 처리 및 μ˜ˆμ™Έ λ°œμƒ λͺ…ν™•νžˆ ν•˜κΈ°
  • 맀직 λ©”μ„œλ“œ μ‚¬μš©λ²•μ€ ν‘œμ€€ 라이브러리 μ½”λ“œ μ°Έμ‘°
  • κ³Όλ„ν•œ μ»€μŠ€ν„°λ§ˆμ΄μ§• ν”Όν•˜κ³  직관적인 μΈν„°νŽ˜μ΄μŠ€ μœ μ§€


⚠️ **GitHub.com Fallback** ⚠️