!pip install multipledispatch
xxx = 2
def x():
xxx = 1
print(xxx)
x()
# 1
Python
Callable
Call: 함수를 호출 한다
Python에서 괄호('()')를 붙일 수 있는 것은 callable 이다
즉, 호출 가능한 함수 또는 객체
1. function(method)
2. class
3. __call__이 정의된 object
LEGB
G: 기본적으로 사용하는 공간은 Global 공간 (global)
B: Builtin이라는 공간에 저장되어 있는 것들
E: Enclosing Function Local, 함수를 내포하는 또 다른 함수 영역
L: Local, 함수 내 정의된 지역변수
python 공간규칙
1. B에 없으면 G에 있는지 찾는다
2. 상위단계(B쪽으로 갈수록 상위)에서 하위단계로 접근할 수 없다
3. 하위단계(L쪽으로 갈수록 하위)에서 상위단계로는 접근할 수 있다
변수 찾는 우선순위 => L > E > G > B
xxx = 2
def x():
xxx = 1
print(xxx)
x()
# 1
xxx = 2
def x():
print(xxx)
x()
# 2
Closure
'함수를 중첩시키고 함수를 리턴하는 함수'. 클로저는 보통 함수를 쉽게 변형할 수 있는 기법이다 # Higher order function 클래스 안에 __call__이 선언되어 있으면 인스턴스가 호출가능해진다(인스턴스( )/__call__메소드가 호출된다)
사실 함수도 클래스의 객체이며 함수를 호출할 때 '함수이름( )'과 같이 사용할 수 있었던 이유가 바로 __call__ 메서드가 선언되어 있기 때문이다
def clo(m):
def inner(n):
return m + n
return inner
class A:
def __init__(self, m):
self.m = m
def __call__(self, n):
return self.m + n
clo(4)(3)
# 7
a = A(3)
a(3)
# 6
import tensorflow as tf
# 4개의 퍼셉트론에 tf.constant([[1,2],[3,4],[5,6]])값을 계산하는 함수
tf.keras.layers.Dense(4)(tf.constant([[1,2],[3,4],[5,6]]))
<tf.Tensor: shape=(3, 4), dtype=float32, numpy=
array([[ 1.57166 , -0.1644063 , 1.6268642 , -0.73175406],
[ 2.9206128 , -0.0049057 , 3.2637818 , -1.5273063 ],
[ 4.2695656 , 0.1545949 , 4.9006996 , -2.3228586 ]],
dtype=float32)>
class B:
def __init__(self, m):
self.m = m
def __call__(self, n):
return self.m + n
B(3)(4)
# 7
def __call__(self, n):
return self.m + n + 1
B.__call__ = x
※ function이라는 데이터 타입도 존재한다
def a(n):
return n
type(a)
# function
Callable Method 종류
1. Instance method 2. classmethod 3. staticmethod
위임 개념은 크게 3가지로 볼 수 있다
1. instance 2. class 3. inheritance
class T:
a = 1 # class variable/attribute 클래스 안에서는 식별자를 변수라고 칭한다
# attribute 클래스 안에 정의 되어 있는 모든 것을 attribute 라고 한다
T.a # 클래스가 어떻게 행동해요? 클래스는 메타 클래스의 인스턴스이기 때문이다
# 1
T.a # 클래스가 어떻게 행동해요? 클래스는 메타 클래스의 인스턴스이기 때문이다
# {'xx': 1}
b.yy # 존재하지 않는 변수에 접근하면 attributeError를 발생시킨다
# AttributeError: 'T' object has no attribute 'yy'
b.a # 인스턴스 변수에 없으면 클래스 변수에서 찾는다 (위임)
# 1
class A:
@classmethod
def xx(cls): # instance / class variable의 생성은 시점에 따라 결정된다
cls.t = 1
print('cls')
def yy(self):
print('instance')
A.xx # classmethod는 클래스 입장에서 함수가 메소드로
# <bound method A.xx of <class '__main__.A'>>
A.yy
<function __main__.A.yy>
a = A()
a.xx() # 인스턴스에 없으면 클래스 찾는다
# cls
a.t
# 1
import pandas as pd
type(pd.DataFrame)
# type
pd.DataFrame.from_dict # classmethod
# <bound method DataFrame.from_dict of <class 'pandas.core.frame.DataFrame'>>
class B:
def aa(self):
self.a = 1
def bb(self):
self.b = 2 # 인스턴스 변수는 인스턴스가 사용한다
b = B()
b.a
# AttributeError: 'B' object has no attribute 'a'
b.aa() # 함수 실행시점에서 인스턴스 변수에 접근 가능해진다
b.a
# 1
vars(b)
# {'a': 1}
class test:
a = 1
@classmethod
def one(cls):
cls.a = 1
print('cls')
def two(self):
self.b = 2
t = test()
t.a
# 1
t.b # 인스턴스 메소드가 실행된 시점 이후에 접근 가능하다
# AttributeError: 'test' object has no attribute 'b'
t.two()
t.b
# 2
import tensorflow as tf
from tensorflow.keras.layers import Dense, Flatten, Conv2D
from tensorflow.keras import Model
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data() # 동적 생성
x_train, x_test = x_train / 255.0, x_test / 255.0
class MyModel(Model):
def __init__(self): # callable 연산자 overloading / 역할은 기능을 초기화 한다
super(MyModel, self).__init__()
self.conv1 = Conv2D(32, 3, activation='relu')
self.flatten = Flatten()
self.d1 = Dense(128, activation='relu')
self.d2 = Dense(10)
def call(self, x):
x = self.conv1(x)
x = self.flatten(x)
x = self.d1(x)
return self.d2(x)
# Create an instance of the model
model = MyModel()
※ 클래스안의 클래스 메소드와 인스턴스 메소드의 가장 큰 차이점은 클래스를 인스턴스화 했을 때 클래스 메소드 안에 있는 클래스 변수는 바로 접근 가능하지만, 인스턴스 메소드 안에 있는 인스턴스 변수는 인스턴스 변수가 실행된 시점 이후에 접근 가능해진다
class C:
def __new__(cls):
print('new')
def __init__(self):
print('init')
C()
# new
c = C()
# new
vars(c)
# TypeError: vars() argument must have __dict__ attribute
class C:
def __new__(cls): # 객체를 반환하는 것
print('new')
return super().__new__(cls)
def __init__(self): # 반환된 객체의 값을 지정해주는 것 / 초기화 용도로 사용 / return이 None이어야 한
print('init')
c = C() # 파이썬에서 인스턴스 생성은 두 단계로 나누어져 있다
# new
# init
staticmethod
대형 프로젝트에서 주로 사용한다
class T:
@staticmethod # 기본적으로 python의 method는 정의 첫번째 인자 강제, 사용은 첫번째 인자 생략하는 것이 원칙이다
def st(): # staticmethos는 클래스 인스턴스와 상관 없이 존재한다
print('st')
T.st() # 체계적으로 구조화 할 수 있다
# st
property, descriptor
descriptor 는 . 행동 결정 (get set del) => 정보 은닉에 사용
class D: # callable 관점에서
def __init__(self, t):
self._t = t
@property # callable을 callable 하지 않게 변경
def t(self):
return self._t
@t.setter
def t(self, t):
self._t = t
def __getattribute__(self, x):
if x == '_t':
print('접근 안됨')
d = D(6)
d.t
vars(d)
d._t
# 접근 안됨
class E:
__a = 1 # mangling
E.__a
# AttributeError: type object 'E' has no attribute '__a'
E._E__a
# 1
Dispatch
Dispatch는 어떤 메소드를 호출할 것인가를 결정하여 그것을 실행하도록 유도해주는 과정을 말한다
python은 singledispatch만 지원한다
단, multiple dispatch는 3rd party를 설치하면 구현 가능하다
파라미터가 한개면 single
파라미터가 두개 이상이면 multiple
len # type builtin_function or method / dispatch를 지원해주는 generic function
len([1,2,3]) -> list 관련 메소드로 dispatch
len((1,2,3)) -> tuple 관련 메소드로 dispatch # dispatch는 tensorflow predict에 숨어있는 개념이다
Single dispatch vs Multiple dispatch
# method overloading
# 다른 프로그래밍 언어에서는 parameter가 다르면 다른 함수로 간주한다
# python에서는 method overloading을 지원하지 않는다
def x():
print('x')
def x(a):
print('a')
Single dispatch
from functools import singledispatch
@singledispatch # 데코레이터 singledispatch함수에 x함수의 기능이 추가 되는 것이다
def x(a):
print(a)
@x.register(int)
def _(a):
print('int', a)
@x.register(float)
def _(a):
print('float', a)
# 데코레이터 관점에서 봤을 때 메소드 이름이 동일해도 서로 다르게 작동할 수 있다
# 데이터 타입에 따라서 다른 메소드를 실행시킬수 있다
x('a')
# a
x(1)
# int 1
x(1.)
# float 1.0
Tensorflow predict (dispatch 예시)
import tensorflow as tf
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(2, input_shape=(2,))
])
model.predict(tf.constant([[1,2]])) # numpy array type
# array([[-0.9186919, -1.4591577]], dtype=float32)
model(tf.constant([[1,2]])) # Tensor type
# <tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[-0.9186919, -1.4591577]], dtype=float32)>
Multiple dispatch
!pip install multipledispatch
from multipledispatch import dispatch
@dispatch(int, int)
def add(x, y):
return x + y
@dispatch(object, object)
def add(x, y):
return "%s + %s" % (x, y)
add(1,2)
# 3
add('1','2')
# '1 + 2'
※ 용어 정리
__함수이름__ 이러한 형태의 메소드: dundu, magic method, speicial method, 일반적으로 프로그래밍 언어에서는 protocol이라고 한다
from itertools import zip_longest
x = zip([1,2,3,4],[4,5,6])
list(x)
# [(1, 4), (2, 5), (3, 6)]
y = zip_longest([1,2,3,4],[4,5,6])
list(y)
# [(1, 4), (2, 5), (3, 6), (4, None)]
'Computer_Science > Visual Intelligence' 카테고리의 다른 글
6일차 - Image 처리 (1) (0) | 2021.09.21 |
---|---|
5일차 - 영상 데이터 처리를 위한 Array 프로그래밍 + image 처리 (0) | 2021.09.18 |
4일차 - 영상 데이터 처리를 위한 객체지향 프로그래밍 (0) | 2021.09.18 |
3일차 - 영상 데이터 처리를 위한 객체지향 프로그래밍 (0) | 2021.09.18 |
1일차 - 영상 데이터 처리를 위한 함수형 패러다임 (0) | 2021.09.16 |