🐍[Python] 맀직 λ©”μ†Œλ“œ - 1

λ“€μ–΄κ°€λ©°

μš°λ¦¬κ°€ μ½”λ“œλ₯Ό μž‘μ„±ν•  λ•Œ, 파이썬이 λ‚΄λΆ€μ μœΌλ‘œ Built-in ν•¨μˆ˜λ₯Ό μˆ˜μ •ν•΄μ„œ μ‚¬μš©ν•˜μ—¬ 되면 μ’€ 더 효율적이 코딩이 κ°€λŠ₯ ν•©λ‹ˆλ‹€. 이것을 맀직 λ©”μ†Œλ“œ ν˜Ήμ€ μŠ€νŽ˜μ…œ λ©”μ†Œλ“œλΌκ³  ν•©λ‹ˆλ‹€.


νŒŒμ΄μ¬μ„ μž˜ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ‹œν€€μŠ€(Sequence), 반볡(Iterator), ν•¨μˆ˜(Functions), 클래슀(Class) 이 4가지 μš”μ†Œλ₯Ό 잘 μ•Œμ•„μ•Ό ν•©λ‹ˆλ‹€.

맀직 λ©”μ†Œλ“œ

클래슀 μ•ˆμ— μ •μ˜ν•  수 μžˆλŠ” νŠΉλ³„ν•œ(Built-in) λ©”μ†Œλ“œλ₯Ό 맀직 λ©”μ†Œλ“œλΌκ³  ν•©λ‹ˆλ‹€.

κΈ°λ³Έν˜•

λ‹€μŒκ³Ό 같이 int λ©”μ†Œλ“œλ₯Ό 좜λ ₯ν•˜λ©΄ μ–΄λ–»κ²Œ λ κΉŒμš”? λ‹€μŒκ³Ό 같이 <class 'int'> 둜 좜λ ₯ λ©λ‹ˆλ‹€. λ‹€μ‹œ 말해 파이썬의 λͺ¨λ“  데이터 νƒ€μž…μ€ 클래슀 μž…λ‹ˆλ‹€. κ·Έλž˜μ„œ ν΄λž˜μŠ€κ°€ μ€‘μš”ν•œ 것 μž…λ‹ˆλ‹€.

print(int)
# <class 'int'>


λͺ¨λ“  속성 및 λ©”μ†Œλ“œ 좜λ ₯

κ·Έλ ‡λ‹€λ©΄ int ν΄λž˜μŠ€μ—λŠ” μ–΄λ–€ 속성듀이 담겨져 μžˆμ„κΉŒμš”?

print(dir(int))
# ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']


μš°λ¦¬κ°€ 이전에 μ‚¬μš©ν–ˆλ˜ λ³€μˆ˜λ“€ λ³΄λ‹€λŠ” 훨씬 더 λ§Žμ€ λ©”μ†Œλ“œλ“€μ„ ν¬ν•¨ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒκ³Ό 같이 n 에 int ν˜• 숫자λ₯Ό μ„ μ–Έ ν•˜κ³  type 을 찍어보면 λ‹€μŒκ³Ό 같이 int class λ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€. 즉, int class 의 λ©”μ†Œλ“œλ“€μ„ μˆ˜μ •ν•˜λ©΄ 보닀 low-levelμ—μ„œ 코딩이 κ°€λŠ₯ν•΄ μ§‘λ‹ˆλ‹€.

n = 10
print(type(n))
# <class 'int'>


λ‹€μŒ μ½”λ”©κ³Ό 같이 + λ₯Ό μ‚¬μš©ν•˜κ±΄, __add__ λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜κ±΄ κ²°κ³Όκ°€ 동일 ν•©λ‹ˆλ‹€. μš°λ¦¬κ°€ λ§μ…ˆμ„ ν•  λ•Œ + 이 μ•„λ‹ˆλΌ __add__ λ₯Ό μ‚¬μš©ν•˜λ©΄ μ–΄λ–¨κΉŒμš”? ꡉμž₯히 μ‚¬μš©ν•˜κΈ° μ–΄λ ΅κ³  가독성도 λ–¨μ–΄ 질 것 μž…λ‹ˆλ‹€. λ•Œλ¬Έμ— 파이썬 μ–Έμ–΄μ—μ„œ 이λ₯Ό wrapping 처리λ₯Ό ν•˜μ—¬ + 으둜 연산이 κ°€λŠ₯ν•˜λ„λ‘ ν•œ 것 μž…λ‹ˆλ‹€.

>>> n = 10
>>> print(n+ 100)
>>> print(n.__add__(100))

# 110
# 110

예제#1

λ‹€μŒκ³Ό 같이 클래슀 μ½”λ“œλ₯Ό μž‘μ„±ν•œλ‹€.

# 클래슀 예제1
class Fruit:
    def __init__(self, name, price) -> None:
        self._name = name
        self._price = price

    def __str__(self) -> str:
        return f'Fruit Class Info {self._name}, {self._price}'

    def __add__(self, x):
        return self._price + x._price


λ‹€μŒκ³Ό 같이 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€.

# μΈμŠ€ν„΄μŠ€ μ‚¬μš©
s1 = Fruit("Orange", 7500)
s2 = Fruit('Banana', 3000)


자 이 λ‘˜μ˜ 과일 가격을 κ³„μ‚°ν•˜λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν• κΉŒ? μΈμŠ€ν„΄μŠ€λ₯Ό 직접 μ ‘μ†ν•΄μ„œ μ—°μ‚°ν•˜λŠ” 것은 맀우 μœ„ν—˜ν•œ 행동이라고 ν–ˆλ‹€. λ˜ν•œ μ½”λ“œμ˜ 양도 λŠ˜μ–΄ λ‚˜κ³  가독성도 λ–¨μ–΄μ§€κ²Œ λœλ‹€.

# 일반적인 μ—°μ‚°
s1._price + s2._price

# 맀직 λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•œ μ—°μ‚°
s1 + s2

μœ„μ™€ 같이 맀직 λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ„ 보호 ν•  수 μžˆμ„ 뿐만 μ•„λ‹ˆλΌ μ½”λ“œμ˜ 가독성도 μ‚΄μ•„λ‚˜κ²Œ λœλ‹€.

예제#2

예λ₯Ό λ“€μ–΄, 2차원 ν‰λ©΄μƒμ˜ μ’Œν‘œλ₯Ό λ§μ…ˆν•˜λŠ” λ¬Έμ œκ°€ μ£Όμ–΄μ‘Œλ‹€κ³  κ°€μ •ν•΄λ³΄μž.

(5,2) + (4,3)  = (9,5)
(10,3) + * 5 = (50, 15)
max((5,10)) = 10


클래슀 κ΅¬ν˜„

class Vector(object):
    ''''''
    def __init__(self,  *args) -> None:
        """Create a vector, example : v = Vector(5,10)"""
        if len(args) == 0:
            self._x, self._y = 0, 0

        else:
            self._x, self._y = args

    def __repr__(self) -> str:
        "Return the Vector information"
        return f"Vector({self._x}, {self._y})"

    def __add__(self, other):
        """Return the vector addition of inputs"""
        return Vector(self._x + other._x, self._y + other._y)

    def __mul__(self, other):
        """Return the vector multiply of inputs"""
        return Vector(self._x * other._x, self._y * other._y)

    def __bool__(self):
        """Check inputs are in 2-D coordinate"""
        return bool(max(self._x, self._y))


좜λ ₯

print(Vector.__init__.__doc__)
# Create a vector, example : v = Vector(5,10)
print(Vector.__add__.__doc__)
# Return the vector addition of inputs


print(v1, v2, v3)
# Vector(5, 7) Vector(23, 35) Vector(0, 0)

print(v1 + v2)
# Vector(28, 42)
print(v1 * v2)
# Vector(115, 245)


dataclasses ν•œ μŠ€ν‘Ό

python의 dataclassesλ₯Ό μ‚¬μš©ν•΄μ„œ μœ„μ—μ„œ μž‘μ„±ν•œ 클래슀λ₯Ό 보닀 더 κ°œμ„  ν•  μžˆμŠ΅λ‹ˆλ‹€.

from dataclasses import dataclass

@dataclass
class Vector(object):
    _x : int = 0
    _y : int = 0

    def __repr__(self) -> str:
        """Return the Vector information"""
        return f"Vector({self._x}, {self._y})"

    def __add__(self, other):
        """Return the vector addition of inputs"""
        return Vector(self._x + other._x, self._y + other._y)

    def __mul__(self, other):
        """Return the vector multiply of inputs"""
        return Vector(self._x * other._x, self._y * other._y)

    def __bool__(self):
        """Check inputs are in 2-D coordinate"""
        return bool(max(self._x, self._y))

    
>>> print(v1, v2, v3)
# Vector(5, 7) Vector(23, 35) Vector(0, 0)
>>> print(v1 + v2)
# Vector(28, 42)
>>> print(v1 * v2)
# Vector(115, 245)

dataclassλ₯Ό μ‚¬μš©ν•˜λ―€λ‘œμ¨, __init__ λ©”μ†Œλ“œμ—μ„œ λ³΅μž‘ν•˜κ²Œ 인자λ₯Ό λ°›μ•„ μ½”λ“œλ₯Ό μž‘μ„± ν•  λ•Œ 보닀. μ½”λ“œμ˜ 가독성이 쒋아지고 μ‚¬μš©μ„±λ„ μ’‹μ•„ μ‘ŒμŠ΅λ‹ˆλ‹€.