π [Python] αα ©α―α α ₯αα ³α―(Callable) αα ’α¨αα ¦ αα ΅αα ’αα ‘αα ΅
on
κ°μ²΄μ μ μ
κ°μ²΄λ νμ΄μ¬μ΄ λ°μ΄ν°λ₯Ό μΆμνν κ²μ λλ€. νμ΄μ¬ νλ‘κ·Έλ¨μ λͺ¨λ λ°μ΄ν°λ κ°μ²΄λ κ°μ²΄ κ°μ κ΄κ³λ‘ ννλ©λλ€. ν° λ Έμ΄λ§(Von Neumann)μ βνλ‘κ·Έλ¨ λ΄μ₯μ μ»΄ν¨ν°(stored program computer)β λͺ¨λΈμ λ°λ₯΄κ³ , λ κ·Έ κ΄μ μμ μ½λ μμ κ°μ²΄λ‘ ννλ©λλ€.
μ½λ¬λΈ(Callabe) κ°μ²΄
μ°λ¦¬κ° νμ΄μ¬ ν¨μλ ν΄λμ€μμ ()
λ₯Ό μ¬μ©νλ μλ―Έλ λͺ¨λ μ½λ¬λΈ(Callable) κ°μ²΄λ₯Ό μλ―Έν©λλ€. νμ΄μ¬μμ λͺ¨λ κ°μ²΄κ° ()
μ¬μ©ν μ μλ μ΄μ κ° λ°λ‘ μ΄κ² λλ¬Έμ
λλ€. μ½λ¬λΈ κ°μ²΄λ§μ΄ ()
λ₯Ό μ¬μ©ν μ μκ³ , μ΄λ __call__
νΉμ μ΄νΈλ¦¬λ·°ν°(λ©μλ)λ₯Ό μ¬μ©νλ κ²κ³Ό μλ―Έκ° κ°μ΅λλ€.
>>> class c(object):
... def f(self): pass
>>> '__call__' in dir(c)
False
>>> '__call__' in dir(c().f)
True
κΈ°λ³Έμ μΌλ‘,c
ν΄λμ€ μμ μλ f
λΌλ λ©μλλ μ½λ¬λΈ κ°μ²΄μ΄κΈ° λλ¬Έμ __call__
λ©μλλ₯Ό ν¬ν¨νκ³ μλ κ²μ
λλ€. νμ§λ§ c
λΌλ ν΄λμ€μλ __call__
μ΄λΌλ λ©μλκ° μ‘΄μ¬νμ§ μμ§λ§ μ½λ¬λΈ κ°μ²΄μ
λλ€. μλνλ©΄, ν΄λμ€ μμ __call__
λ©μλλ₯Ό μ μΈν μ μκΈ° λλ¬Έμ΄μ£ .
>>> class c(object):
... def f(self):
... pass
... def __call__(self):
... print("callable")
...
>>> '__call__' in dir(c)
True
κ·ΈλΌ Python μΈν°ν리ν°μμ c
μ λ¨λ
μΌλ‘ μ¬μ©ν λμ, c()
μ κ°μ΄ μ½λ¬λΈ κ°μ²΄λ‘ μ¬μ©νλ©΄ μ΄λ€μ μ΄ λ€λ₯Έ κ±ΈκΉμ? κ·Έκ²μ λ°λ‘ κ°μ²΄μ μ¬μ©μ μ 무μ
λλ€. ()
λ₯Ό μ¬μ©νμ§ μκ³ c
λ₯Ό λ¨λ
μΌλ‘ μ¬μ©νκ² λλ€λ©΄ ν΄λμ€κ° μ μ₯λ κ°μ²΄ μ£Όμλ₯Ό λ°ν νκ² λ©λλ€. λ°λ©΄, c()
μ κ°μ΄ μ½λ¬λΈ κ°μ²΄λ‘ μ¬μ©νκ² λλ€λ©΄ ν΄λμ€μ νΈμΆμ΄ μΌμ΄λκ³ νμ΄μ¬μ ν΄λΉ ν΄λμ€ κ°μ²΄μ μ£Όμλ₯Ό μ°Ύμκ° μμ±κ³Ό μλ©Έμ΄ μΌμ΄λκ²λ©λλ€. λλ¬Έμ, ν΄λμ€λ₯Ό νΈμΆ ν λ λ§λ€ μλ‘μ΄ μ£Όμκ° κ°μ²΄λ‘ λ°νλλ κ²μ΄μ£ .
>>> class c(object):
... def f(self): pass
>>> t = C()
>>> t
<__main__.C object at 0x10c932940> # μ£Όμλ₯Ό κ°μ²΄λ‘ λ°ν
>>> t = C()
>>> t
<__main__.C object at 0x10ca152e0> # ν΄λμ€λ₯Ό νΈμΆ ν λλ§λ€ μλ‘μ΄ μ£Όμλ₯Ό κ°μ²΄μ λ°ν
>>> C
<class '__main__.C'>
ν΄λμ€μμ ()
μ μλ―Έ
ν΄λμ€λ₯Ό νΈμΆ ν λ μΌλ°μ μΌλ‘ insatnce = C()
μ κ°μ΄ ()
λ₯Ό μ¬μ©ν΄μ μΈμ€ν΄μ€λ₯Ό ν λΉν©λλ€. μ¦, ν΄λμ€λ₯Ό νΈμΆ νλ κ²μ΄μ§μ(=μ½λ¬λΈ κ°μ²΄λ₯Ό νΈμΆ). κ·Έλ λ€λ©΄ ν΄λμ€λ ν¨μμΈ κ²μΌκΉμ? μ ννλ ν¨μλ νΌμ€νΈ ν΄λμ€λ‘ ν¨μκ° ν΄λμ€μ μΌμ’
μ
λλ€. κ·Έλ λ€λ©΄ ν΄λμ€λ₯Ό νΈμΆμ μν μ 무μμΌκΉμ?
ν΄λμ€ μμ±μ
νμ΄μ¬μμμ ν΄λμ€ μμ±μμ μλ©Έμμ κ΄ν΄ μμλ³΄κ² μ΅λλ€. μμ±μλ μ΄λ¦μμ μ μ μλ―μ΄ κ°μ²΄κ° λ§λ€μ΄μ§ λ νΈμΆλλ ν¨μλ₯Ό μμ±μλΌκ³ μ΄μΌκΈ° νλ©°, κ°μ²΄κ° μ¬λΌμ§ λ νΈμΆλλ ν¨μλ₯Ό μλ©ΈμλΌκ³ μ΄μΌκΈ°ν©λλ€.
μ°λ¦¬κ° ν΄λμ€λ₯Ό μ¬μ©ν λ νν μ¬μ©νλ __init__
μ΄ λ°λ‘ μμ±μ μλκ²μ΄μ§μ. μ°λ¦¬κ° ν΄λμ€λ₯Ό ()
λ₯Ό μ¬μ©ν΄μ νΈμΆνκ² λλ©΄ νμ΄μ¬μ μλμΌλ‘ μ μΌ λ¨Όμ __init__
μ μ°Ύμμ¬ μ΄ λ©μλλ₯Ό μ€νμν€λ κ²μ΄μ§μ. μ΄μ°λ 보면 ν¨μμ μνκ³Όλ λΉμ·ν©λλ€.
κ° λ©μλ κΈ°λ₯λ€ μ΄ν΄ 보기
λ€μκ³Ό κ°μ΄ ν΄λμ€λ₯Ό μμ±νκ³ κ° λ©μλμ κΈ°λ₯λ€μ μ΄ν΄ λ³΄κ² μ΅λλ€.
>>> class C:
... def __init__(self): # μμ±μ
... print('__init__ method')
... def __call__(self): # μ½λ¬λΈ κ°μ²΄ μ€μ
... print('__call__ method')
... def special_method(self): # λ©μλ
... print('special method')
... def __del__(self): # μλ©Έμ
... print('__del__ method')
ν΄λμ€λ₯Ό νΈμΆνκ² λλ©΄ κ°μ₯ λ¨Όμ __init__
λ©μλκ° κ°μ₯ λ¨Όμ μ€νλκ³ μ΄ν, μ€νλ κ°μ²΄μ μ£Όμκ° λ°ν λ©λλ€.
>>> C() # ν΄λμ€ νΈμΆ
__init__ method
<__main__.C object at 0x1062208b0>
del
μ μΈμ€ν΄μ€λ₯Ό μμ νλ νμ΄μ¬ λ΄μ₯ν¨μ μ
λλ€. ν λΉλ μΈμ€ν΄μ€κ° μ‘΄μ¬νμ§ μμΌλ μ€λ₯λ₯Ό λνλ΄λ κ²μ
λλ€. μ¬κΈ°μ μ€λ₯ λ©μΈμ§λ₯Ό μ΄ν΄ 보면 βcannot delete function callβ μ νμΈ ν μ μμ΅λλ€. μμμ μ€λͺ
ν ν΄λμ€μ νΈμΆμ΄ ν¨μμ νΈμΆκ³Ό λΉμ·ν μ±κ²©μ΄λΌκ³ νμλκ²κ³Ό μΌμΉνλ λΆλΆμΈκ²μ νμΈ ν μ μμ΅λλ€.
>>> del C()
File "<input>", line 1
del C()
^
SyntaxError: cannot delete function call
κ·Έλ λ€λ©΄ νΈμΆμ νΈμΆλ κ°λ₯ ν κΉμ? μμμ __call__
λ©μλλ₯Ό μ¬μ©νμ¬ μ½λ¬λΈ κ°μ²΄λ₯Ό μ μ ν΄μ€¬κΈ° λλ¬Έμ κ°λ₯ ν©λλ€. μ¬κΈ°μ __del__
λ©μλκ° μ€νλ κ²μ νμ΄μ¬μμ κ°μ²΄κ° μΈμ€ν΄μ€μ ν λΉ λμ§ μμμ§ λλ¬Έμ λ©λͺ¨λ¦¬ λμλ₯Ό λ°©μ§νκ³ μ μλμΌλ‘ ν λΉλμ§ λͺ»ν κ°μ²΄λ₯Ό μ κ±° νκ²μ
λλ€.
>>> C()()
__init__ method
__call__ method
__del__ method
t
λ³μμ μΈμ€ν΄μ€λ₯Ό ν λΉνλ©΄ λ€μκ³Ό κ°μ΅λλ€. __call__
μ μ¬μ©ν΄μ μ½λ¬λΈ κ°μ²΄λ‘ μ μ ν΄μ€¬κΈ° λλ¬Έμ t
μΈμ€ν΄μ€λ μ½λ¬λΈ μΈμ€ν΄μ€λ‘ μ¬μ©νκ² λκ² μ
λλ€. μ΄ν, del
λ΄μ₯ν¨μλ₯Ό μ¬μ©ν΄μ μΈμ€ν΄μ€λ₯Ό μ κ±° ν μ μμ΅λλ€.
>>> t = C()
__init__ method
>>> t.special_method()
special method
>>> t() # μ½λ¬λΈ μΈμ€ν΄μ€
__call__ method
>>> del t
__del__ method
ν¨μμ ()
μ ν΄λμ€μ ()
μ λΉκ΅
κ·Έλ λ€λ©΄ λ©μλ(ν¨μ)μμμ ()
μ¬μ©κ³Ό ν΄λμ€μμμ ()
μ¬μ©μ μ΄λ ν μ°¨μ΄μ μ΄ μμκΉμ?
νΌμ€νΈ ν΄λμ€ ν¨μ (First-class function)
νΌμ€νΈν΄λμ€ ν¨μλ νλ‘κ·Έλλ° μΈμ΄κ° ν¨μ (function) λ₯Ό first-class citizenμΌλ‘ μ·¨κΈνλ κ²μ λ»ν©λλ€. μ½κ² μ€λͺ νμλ©΄ ν¨μ μ체λ₯Ό μΈμ (argument) λ‘μ¨ λ€λ₯Έ ν¨μμ μ λ¬νκ±°λ λ€λ₯Έ ν¨μμ κ²°κ³Όκ°μΌλ‘ λ¦¬ν΄ ν μλ μκ³ , ν¨μλ₯Ό λ³μμ ν λΉνκ±°λ λ°μ΄ν° ꡬ쑰μμ μ μ₯ν μ μλ ν¨μλ₯Ό λ»ν©λλ€.
μ μ μμμ μ€μνκ² μ΄ν΄λ΄μΌν μ 보λ first-class citizen λΌλ κ²μ λλ€. νΌμ€νΈ ν΄λμ€ μν°μ¦μ΄λΌλ κ²μ΄ 무μμ μλ―Ένλ κ²μΌκΉμ?
μμμ νμ΄μ¬ νλ‘κ·Έλλ°μ ν° λ Έμ΄λ§μ΄ μ€κ³ν κ°μ²΄μ κ°λ μ μ¬μ©νμ¬ μ΄μλ©λλ€. νλ‘κ·Έλλ°μ ν λ λλΆλΆμ κΈ°λ₯(ν¨μ, ν΄λμ€..)λ€μ κ°μ²΄ λ¨μλ‘ κ΅¬μ±λκ³ μ€νλμ΄μΌ νλ€λ λ»μ΄μ§μ. νμ§λ§ λ¨μν λ§μ κΈ°λ₯μ ꡬννκΈ° μν΄μ κ°μ²΄ λ¨μλ‘ νλ‘κ·Έλλ°μ νλ©΄ κ΅μ₯ν λΉν¨μ¨μ μΌ κ²μ λλ€.
μλ₯Ό λ€μ΄ λ€μκ³Ό κ°μ΄ λ§μ ν¨μλ₯Ό μ μ νλ€κ³ κ°μ ν΄ λ΄ λλ€. λ€μκ³Ό κ°μ΄ λ¨μνκ² ν¨μλ₯Ό μ μΈνμ¬ μ¬μ©ν μ μμ΅λλ€.
>>> def add(a,b):
... return a+b
...
>>> add(2,3)
5
νμ§λ§, κ°μ²΄λ₯Ό μ¬μ©ν΄μ μ΄ ν¨μλ₯Ό μ μ νλ€λ©΄ μ΄λ»κ² ν΄μΌ ν κΉμ? μ°λ¦¬κ° μμμ νλ κ°μ²΄λ₯Ό μ½λ¬λΈ κ°μ²΄λ‘ λ§λ€μ΄μ μμ±ν΄μΌ ν©λλ€.
>>> class C(object):
... def __call__(self, a, b):
... return a + b
...
>>> t = C() # μΈμ€ν΄μ€ μμ±
>>> add = C() # μΈμ€ν΄μ€ νΈμΆ
>>> add(2,3)
5
νμ΄μ¬μμλ μ΄λ¬ν κ°μ²΄ μ§ν₯μ νλ‘κ·Έλλ°μ νΌνκ³ μ ν¨μμ κΈ°λ₯(μΈμ, λ°ν)μ 미리 νλμ κ°μ²΄λ‘ μ€μ ν΄ λμ΄ λ³΅μ‘ν νλ‘κ·Έλλ°μ λ°©μ§ νκ² μ λλ€.
λΆλ‘
μΈμ€ν΄μ€ λ©μλ(Instance methods)
μΈμ€ν΄μ€ λ©μλλ ν΄λμ€, ν΄λμ€ μΈμ€ν΄μ€μ λͺ¨λ μ½λ¬λΈ κ°μ²΄ (λ³΄ν΅ μ¬μ©μ μ μ ν¨μ)μ κ²°ν©ν©λλ€. μ¬κΈ°μ μΈμ€ν΄μ€μ μλ―Έλ κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°(OOP)μμ ν΄λΉ ν΄λμ€μ κ΅¬μ‘°λ‘ μ»΄ν¨ν° μ μ₯곡κ°μμ ν λΉλ μ€μ²΄λ₯Ό μλ―Έν©λλ€.
μΈμ€ν΄μ€ λ©μλ κ°μ²΄κ° νΈμΆλ λ, κΈ°λ°μ λλ ν¨μ (__func__
) κ° νΈμΆλλλ°, μΈμ λͺ©λ‘μ μμ ν΄λμ€ μΈμ€ν΄μ€ (__self__
) C.κ° μ½μ
λ©λλ€. μλ₯Ό λ€μ΄, C
κ° ν¨μ f()
μ μ μλ₯Ό ν¬ν¨νλ ν΄λμ€μ΄κ³ , x
κ° C
μ μΈμ€ν΄μ€μΌ λ, x.f(1)
λ₯Ό νΈμΆνλ κ²μ C.f(x, 1)
μ νΈμΆνλ κ²κ³Ό κ°μ΅λλ€.
μ¬κΈ°μ, selfλ₯Ό λΆμΈ μͺ½μ bound, μ λΆμΈ μͺ½μ unbound λ©μλλΌ ν©λλ€.
μμ
>>> class C:
... def method_one():
... print("method one called")
... def method_two(self):
... print("method two called")
... @staticmethod # μ μ λ©μλ
... def method_three():
... print("method three called")
μμ μ½λλ₯Ό μμ μ½λλ‘ μ¬μ©νκ³ μ ν©λλ€. method_three()
λ λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμ¬ μ μ λ©μλλ‘ μ¬μ©ν©λλ€. μ΄ λ©μλλ₯Ό μ¬μ©νλ©΄ method_three()
λ₯Ό bound methodλ‘ λ§λ€μ§ λ§λΌκ³ μ€μ ν μ μμ΅λλ€.
method_one()
μ μ€νν κ²°κ³Όλ λ€μκ³Ό κ°μ΅λλ€.
>>> C.method_one
<function C.method_one at 0x10ca07b80> # λ¨μ κ°μ²΄μ μ£Όμ λ°ν
>>> C.method_one()
method one called # Cμ μΈμ€ν΄μ€κ° μ‘΄μ¬νμ§ μκΈ° λλ¬Έμ μ€ν κ°λ₯
>>> C.method_one(t)
Traceback (most recent call last):
File "<input>", line 1, in <module>
C.method_one(t)
TypeError: method_one() takes 0 positional arguments but 1 was given
λ€μμΌλ‘
method_two(self)
λ₯Ό μ€νν κ²°κ³Όλ λ€μκ³Ό κ°μ΅λλ€.
>>> C.method_two(t) # t = C(); t.method_two()μ κ°μ μλ―Έ
method two called
>>> C.method_two()
Traceback (most recent call last):
File "<input>", line 1, in <module>
C.method_two()
TypeError: method_two() missing 1 required positional argument: 'self'
μ¬κΈ°μ λμ¬κ²¨ λ΄μΌν μ½λλ C.method_two(t)
μ
λλ€. μ°λ¦¬λ μ΄μ μ ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό ν λΉν λ€μ μΈμ€ν΄μ€μ λ©μλλ₯Ό νΈμΆ νμμ΅λλ€. ν΄λμ€ λ΄λΆμμ self
λΌλ μΈμλ₯Ό μ μΈ νμ§λ§ ν΄λΉ λ©μλλ₯Ό μ¬μ©ν λ, μΈμλ‘ κ°μ λ£μ΄μ£Όμ§ μμλ μ€νμ΄ κ°λ νμ΅λλ€. μλνλ©΄ νμ΄μ¬μμλ μΈμ€ν΄μ€μ λ©μλκ° νΈμΆ(call)λλ©΄ μλμΌλ‘ μΈμ€ν΄μ€ κ°μ²΄λ₯Ό ν΄λΉ λ©μλμ μΈμ μ¦ self
λ‘ λ겨주μλ κ²μ
λλ€.
κ·Έλ¬λ―λ‘ C.method_two(t)
μ μλ―Έλ μΈμ€ν΄μ€λ₯Ό λ³μμ ν λΉνμ§ μκ³ , λͺ
μμ μΌλ‘ self
λΌλ λ³μμ μΈμ€ν΄μ€λ‘ μ¬μ©ν λ³μλ₯Ό μ§μ΄ λ£μ΄ μ΄λ₯Ό μ€ν ν κ²μ΄μ§μ.
t = C()
t.method_two()