classA:def__repr__(self):return'REPR'def__str__(self):return'STR'
a = A()
a # 이름을 부르면 __repr__가 호출된다 # REPRprint(a) # 이름을 print하면 __str__이 호출된다 / escape를 처리해준다 # STR
※ self를 붙이는 이유
classA:def__init__(this):# self 대신 다른 것 사용 가능 그러나 pep8에서 self 사용 권장 print('a')
def__call__(self):# 객체 지향에서 self는 인스턴스(object)를 뜻한다 print('call')
defaa(self):print('aa')
# python 내부에서 c기반으로 작동하기 때문에 (c는 method 개념이 없다) 이와 같이 만들어 졌다
a = A()
A.aa(a) # 어떤 인스턴스에 대해서 사용할 것인가 인자가 필요 / version 1 / 주체가 class A
a.aa(a) # 인스턴스가 주체이고 싶을 때 / argument가 중복되기 때문에 a 생략하게 만들었다
a.aa()
classA:
x = 1classB:
x = 2classC(A,B):pass# method resolution order (python2.2 부터 지원)
C.mro()
# [__main__.C, __main__.A, __main__.B, object]
C.__mro__
# (__main__.C, __main__.A, __main__.B, object)
C.x # C에 없어서 그 다음 우선순위인 A에서 찾는다 # 1
다이아몬드 문제
classA:passclassB(A):passclassC(A):passclassD(A, B):pass# 이런 경우 메소드의 실행순서를 정할 수 없다 # TypeError: Cannot create a consistent method resolution order (MRO) for bases A, B
실행 순서는 D -> B -> C -> A 인데 출력 결과는 왜 반대일까? 그 이유는 바로 super사용시 stack에 들어가기 때문이다
※ Stackoverflow
deffib(n):return fib(n-1) + fib(n-2) if n>2else1# 재귀적으로 계산되는 중간 과정은 stack영역에 저장된다 => 중간 과정에서 중복되는 연산이 많이 쌓인다 => stack에 많이 쌓여 넘치는 것을 stackoverflow # 그러나 python에서는 overflow가 없다
fib(10)
# 55
import sys
sys.maxsize
# 9223372036854775807
sys.maxsize + 1# 정수형은 stackoverflow가 없는 대신에 내부적으로 현재 남아있는 만큼의 가용 메모리를 모두 수 표현에 끌어다 쓴다. 따라서 정수형 연산은 속도(성능)가 매우 느리다 # 9223372036854775808
sys.float_info
# sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)0.1 + 0.1 + 0.1# 0.300000000000000041.7976931348623157e+308 == 1.7976931348623157e+308 + 1# 근사적으로 계산하기 때문에 속도가 빠르다 # True
a == a + 1 # infinity
Duck Typing
미운오리새끼 이야기에서 유래가 되어 오리가 아닌데 오리처럼 행동을 하면 오리라고 간주한다는 개념이다
타입을 미리 정하지 않고 실행되었을 때 해당 Method들을 확인하여 타입을 정한다
'장점'
-타입에대해자유롭다
-상속을하지않아도상속을한것처럼클래스의메소드사용이가능하다
'단점'
-원치않는타입이들어갈경우오류가발생할수있다
-오류발생시원인을찾기어려울수있다
-호환성떨어짐=>추상클래스로대체
-코딩많이해야함
Composition
상속을 하지 않고 클래스내에 객체를 불러와 다른 클래스의 일부 기능을 사용하는 방법.
상속의 위험부담을 줄일 수 있다
classSecurityDoor:
locked = Truedef__init__(self, number, status):
self.door = Door(number, status) # Door의 객체를 갖게 한다defopen(self):if self.locked:
return
self.door.open()
def__getattr__(self, attr):# try except와 비슷returngetattr(self.door, attr) # Door의 attr를 가져와라 (상속을 비슷하게 사용)classComposedDoor:def__init__(self, number, status):
self.door = Door(number, status)
def__getattr__(self, attr):# 없으면 가져와라returngetattr(self.door, attr) # 바꾸지 않고 불러와서 사용할 때
Meta class
type => 모든 클래스의 행동을 결정해준다 클래스의 행동을 바꾸고자 할때 사용하는 클래스
type('int2', (int,), {}) # __main__ 메소드가 있다면 현재 내 작업 공간에서 만든 것이라는 의미이다 # __main__.int2
a = type('int2', (int,), {})
type(a)
# type
classA:# attribute(클래스안에 정의된 모든 것) vs property (descriptor)pass
%whos # 현재 작업 공간에 어떤 객체가 있는가 확인 할때 사용 #
Variable Type Data/Info
-------------------------------
A type <class '__main__.A'>
atype <class '__main__.int2'>
drivemodule <module 'google.colab.dri<...>s/google/colab/drive.py'>
itertoolsmodule <module 'itertools' (built-in)>
%who_ls
['A', 'a', 'drive', 'itertools']
%lsmagicAvailablelinemagics:
%alias %alias_magic %autocall %automagic %autosave %bookmark %cat %cd %clear %colors %config %connect_info %cp %debug %dhist %dirs %doctest_mode %ed %edit %env %gui %hist %history %killbgscripts %ldir %less %lf %lk %ll %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %ls %lsmagic %lx %macro %magic %man %matplotlib %mkdir %more %mv %notebook %page %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %pip %popd %pprint %precision %profile %prun %psearch %psource %pushd %pwd %pycat %pylab %qtconsole %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %rm %rmdir %run %save %sc %set_env %shell %store %sx %system %tb %tensorflow_version %time %timeit %unalias %unload_ext %who %who_ls %whos %xdel %xmode
Available cell magics:
%%! %%HTML %%SVG %%bash %%bigquery %%capture %%debug %%file %%html %%javascript %%js %%latex %%perl %%prun %%pypy %%python %%python2 %%python3 %%ruby %%script %%sh %%shell %%svg %%sx %%system %%time %%timeit %%writefile
Automagic is ON, % prefix IS NOT needed for line magics.
A # REPR(Representation / 이름을 부르면 표현해 주세요) => 메모리에 저장되어 있는 것 부른다 # __main__.A
※ Error
1.NameError : 이름이없을때
2.AttributeError : attribute가없을때, 기능자체가없을때
import tensorflow as tf
model = tf.keras.models.Sequential()
model.summary() # 실행하는 시점에 따라서 인스턴스 변수가 다르게 갖기 때문에 / 값이 없기 때문에 valueError # ValueError: This model has not yet been built. Build the model first by calling `build()` or calling `fit()` with some data, or specify an `input_shape` argument in the first layer(s) for automatic build.
model(tf.constant([[1,2]]))
# <tf.Tensor: shape=(1, 2), dtype=int32, numpy=array([[1, 2]], dtype=int32)>
model.summary()
#
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
Total params: 0
Trainable params: 0
Non-trainable params: 0
_________________________________________________________________
layer = tf.keras.layers.Dense(1)
layer.summary()
# AttributeError: 'Dense' object has no attribute 'summary'classA:
t = 1deftt(self):print('t')
getattr(A, 't') # A에서 t접근 해주세요 # 1
a = A()
getattr(A, 'tt')(a)
# 1
변수와 상수가 구분이 있는 언어라면 상수는 재할당 할 수 없다
python은 변수와 상수를 구분하지 않는다
따라서 tensorflow에서는 이를 구분하기 위해 constant와 variable을 추가적으로 만들었다
cc = tf.constant([1,2,3]) # 상수
dd = tf.Variable([1,2,3]) # 변수
dd.assign_add([2,3,4])
# <tf.Variable 'UnreadVariable' shape=(3,) dtype=int32, numpy=array([3, 5, 7], dtype=int32)>import numpy as np
x = np.array([1,2,3])
x
# array([1, 2, 3])print(x)
# [1 2 3]
Python의 *
1.number*, **
-3*3# 곱하기
-3**3# 제곱
2.sequence*
3.assignment (binding) : unpacking
-x,y,*z=1,2,3,4# unpacking에서 나머지
4.parameter*name
-defx(*b): # 인자의 갯수 제한을 두지 않는다 returnb
5.parameter*
-defname(*,a,b): # keyword only *다음엔 keyword를 사용해야 한다
returna+b# positional 방식 다음에 keyword 방식을 써야 한다
6.parameter**
-defy(**b): # Variable Keywordreturnb7.argument*
-defa(*b):
returnbx= [1,2,3,4] a(*x) # argument unpacking
8.argument**
-defaa(**b):
returnby= {'a': 1, 'b' : 2} aa(**)
9.import에서모두
-import*
※ def t(a, *b)이런 형태를 자주 쓰는 이유
deft(*a, **b):
print(a)
print(b)
# parameter, argument를 정확히 맞출 필요가 없음, 인터페이스의 유연성을 위해
defclo(m):definner(n):return m + n
return inner
classA: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
classB:def__init__(self, m):
self.m = m
def__call__(self, n):return self.m + n
B(3)(4)
# 7def__call__(self, n):return self.m + n + 1
B.__call__ = x
※ function이라는 데이터 타입도 존재한다
defa(n):return n
type(a)
# function
Callable Method 종류
1.Instancemethod2.classmethod3.staticmethod
위임 개념은 크게 3가지로 볼 수 있다
1.instance2.class3.inheritance
classT:
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
classA: @classmethod defxx(cls):# instance / class variable의 생성은 시점에 따라 결정된다
cls.t = 1print('cls')
defyy(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'>>
classB:defaa(self):
self.a = 1defbb(self):
self.b = 2# 인스턴스 변수는 인스턴스가 사용한다
b = B()
b.a
# AttributeError: 'B' object has no attribute 'a'
b.aa() # 함수 실행시점에서 인스턴스 변수에 접근 가능해진다
b.a
# 1vars(b)
# {'a': 1}
classtest:
a = 1 @classmethoddefone(cls):
cls.a = 1print('cls')
deftwo(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.0classMyModel(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)
defcall(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()
※ 클래스안의 클래스 메소드와 인스턴스 메소드의 가장 큰 차이점은 클래스를 인스턴스화 했을 때 클래스 메소드 안에 있는 클래스 변수는 바로 접근 가능하지만, 인스턴스 메소드 안에 있는 인스턴스 변수는 인스턴스 변수가 실행된 시점 이후에 접근 가능해진다
classC:def__new__(cls):print('new')
def__init__(self):print('init')
C()
# new
c = C()
# newvars(c)
# TypeError: vars() argument must have __dict__ attribute
classC:def__new__(cls):# 객체를 반환하는 것print('new')
returnsuper().__new__(cls)
def__init__(self):# 반환된 객체의 값을 지정해주는 것 / 초기화 용도로 사용 / return이 None이어야 한print('init')
c = C() # 파이썬에서 인스턴스 생성은 두 단계로 나누어져 있다 # new# init
staticmethod
대형 프로젝트에서 주로 사용한다
classT: @staticmethod # 기본적으로 python의 method는 정의 첫번째 인자 강제, 사용은 첫번째 인자 생략하는 것이 원칙이다 defst():# staticmethos는 클래스 인스턴스와 상관 없이 존재한다 print('st')
T.st() # 체계적으로 구조화 할 수 있다 # st
property, descriptor
descriptor 는 . 행동 결정 (get set del) => 정보 은닉에 사용
classD:# callable 관점에서def__init__(self, t):
self._t = t
@property # callable을 callable 하지 않게 변경deft(self):return self._t
@t.setterdeft(self, t):
self._t = t
def__getattribute__(self, x):if x == '_t':
print('접근 안됨')
d = D(6)
d.t
vars(d)
d._t
# 접근 안됨
classE:
__a = 1# mangling
E.__a
# AttributeError: type object 'E' has no attribute '__a'
E._E__a
# 1
Dispatch
Dispatch는어떤메소드를호출할것인가를결정하여그것을실행하도록유도해주는과정을말한다
python은singledispatch만지원한다
단, multipledispatch는3rdparty를설치하면구현가능하다
파라미터가한개면single
파라미터가두개이상이면multiple
len# type builtin_function or method / dispatch를 지원해주는 generic function
# method overloading# 다른 프로그래밍 언어에서는 parameter가 다르면 다른 함수로 간주한다 # python에서는 method overloading을 지원하지 않는다 defx():print('x')
defx(a):print('a')
Single dispatch
from functools import singledispatch
@singledispatch # 데코레이터 singledispatch함수에 x함수의 기능이 추가 되는 것이다 defx(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
a = [1,2,3]
b = iter(a) # __next__ 가 생기고 next를 사용할 수 있게 된다 (iterators)next(b)
# 1for i in [1,2,3]: # for문에 들어간 iterable한 객체는 iterator로 변환후 사용된다 print(i)
# 1# 2# 3
Lazy Evaluation
Lazy Evaluation은 계산 결과 값이 필요할 때까지 계산을 늦추는 방식이다 (next로 호출하는 순간 메모리에 올라간다) Lazy Evaluation은 속도가 느리다는 단점이 있지만 파이썬에서는 내부적으로 최적화 되어 있어 속도가 빠르다 메모리의 효율성을 위해 사용한다
a = [1,2,3]
b = iter(a) # next 호출하기 전까지 메모리에 올라가지 않는다 / next호출 시에만 실행
b[0] # iterator로 만들면 sequence한 성질을 잃는다 # 'list_iterator' object is not subscriptable
a = range(10)
b = iter(a)
next(b)
# 0list(b)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]next(b)
# list를 통해 나머지 요소가 전부 출력 되었으므로 더 이상 남아있는 데이터가 없어서 StopIterationError가 발생한다 # StopIteration:
a = (x for x inrange(10)) # 메모리 번지가 표시될 경우 iterator 또는 generator인 경우가 많다
a
# <generator object <genexpr> at 0x7fad65698cd0>
Yield 방식
defx():yield1yield2
y = x()
next(y)
# 1next(y)
# 2
%%writefile a.txt
abcdefg
123123
dfskjfdskjl
# Writing a.txt
b = open('a.txt')
next(b)
# 'abcdefg \n'
b.close()
next(b) # 파일 읽기를 종료했기 때문에 더 이상 불러올 수 없다
ValueError: I/O operation on closed file.
import tensorflow as tf
tf.keras.preprocessing.image.I
[x for x inrange(10)]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[(x, y) for x inrange(5) for y inrange(6,10)] # 여러 개의 데이터를 동시에 생성할 때
[(0, 6),
(0, 7),
(0, 8),
(0, 9),
(1, 6),
(1, 7),
(1, 8),
(1, 9),
(2, 6),
(2, 7),
(2, 8),
(2, 9),
(3, 6),
(3, 7),
(3, 8),
(3, 9),
(4, 6),
(4, 7),
(4, 8),
(4, 9)]
[x for x inrange(10) if x%2 ==0]
# [0, 2, 4, 6, 8]
[x+1for x inrange(5)] # 기존에 있는 데이터를 변경시킬 때
Accumlation pattern
# 초기 값에서 값을 누적하며 저장하는 방식
temp = 0for i inrange(1, 11):
temp += 1
temp
# 10
temp = []
for i inrange(10):
temp.append(i)
temp
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 일반적인 재귀용법 defsumrange(m, n):if m <= n:
return m + sumrange(m+1, n)
else:
return0
sumrange(1,960)
# 461280
# 꼬리 재귀용법defsumrange(m, n):defloop(m, total):if m <= n:
return loop(m+1, m+total)
else:
return total
return loop(m, 0)
sumrange(1,960)
# 461280
Map & Filter & Reduce (Higher order functioin)
Map
iterable에있는모든요소에function을적용하여그결과를반환한다
map을사용하면lazyevaluation로진행해서메모리를크게절약할수있다
연산결과는mapiterator객체로리턴한다
-Deeplearning/Bigdata에서주로사용한다
defa(x):return x + 1list(map(a,[1,2,3]))
# [2, 3, 4]
a = map(lambda x : x+1, [1,2,3,4]) # 로직에 집중할 수 있다는 장점이 있다 '__next__'indir(a)
# Truelist(a)
# [2, 3, 4, 5]
import seaborn as sns
tips = sns.load_dataset('tips')
tips.tip.apply(lambda x:x+1) # 많은 데이터를 한번에 전처리 할때 자주 쓰인다 02.0112.6624.5034.3144.61
...
2396.922403.002413.002422.752434.00
Name: tip, Length: 244, dtype: float64
Filter
predicatefunction함수
iterable객체에있는요소중조건에맞게TrueorFalse를되돌려주는함수
전체데이터에서필요한데이터만뽑아내는함수
defb(x):return x > 3list(filter(b,[1,2,3,4,5,6]))
# [4, 5, 6]
x = filter(lambda x:x>2, [1,2,3,4]) #필요한 데이터만 뽑아낸다 list(x)
# [3, 4]
Reduce
iterable객체의여러개값을하나의값으로축약하여표현할때사용한다
machinelearning, deeplearning에서자주쓰는함수
통계에서전체값중에서하나의대표값을표현하는경우가많기때문에reduce를자주사용한다
from functools import reduce
reduce(lambda x,y:x+y,[1,2,3,4,5])
# 15
import tensorflow as tf
tf.reduce_mean([1,2,3,]) # multiprocessin 기법을 사용할 수 있기 때문에 속도를 향상시킬수 있다
<tf.Tensor: shape=(), dtype=int32, numpy=2>
defx(a):# 여기서 함수는 x return a
# opencv의 rectangle()을 이용하여 시각화# rectangle()은 이미지와 좌상단 좌표, 우하단 좌표, box컬러색, 두께등을 인자로 입력하면 원본 이미지에 box를 그려줌. # bounding box 섹상 지정
green_rgb = (125, 255, 51)
# 노트북형태라 메모리 꼬일것 때문에 copy
img_rgb_copy = img_rgb.copy()
for rect in cand_rects:
# tuple bounding box 좌표 찍기
left = rect[0]
top = rect[1]
# rect[2], rect[3]은 절대적인 수치(너비와 높이)이므로 우하단 좌표를 구하기 위해 좌상단 좌표에 각각을 더함.
right = left + rect[2]
bottom = top + rect[3]
# bounding box 표시하기
img_rgb_copy = cv2.rectangle(img_rgb_copy, (left, top), (right, bottom), color=green_rgb, thickness=2)
plt.figure(figsize=(8, 8))
plt.imshow(img_rgb_copy)
plt.show()
너무 많은 bounding box
# bounding box의 크기가 큰 후보만 추출
# 크기가 10000이상인 애만
cand_rects = [cand['rect'] for cand in regions if cand['size'] > 10000]
green_rgb = (125, 255, 51)
img_rgb_copy = img_rgb.copy()
for rect in cand_rects:
left = rect[0]
top = rect[1]
# rect[2], rect[3]은 너비와 높이이므로 우하단 좌표를 구하기 위해 좌상단 좌표에 각각을 더함.
right = left + rect[2]
bottom = top + rect[3]
img_rgb_copy = cv2.rectangle(img_rgb_copy, (left, top), (right, bottom), color=green_rgb, thickness=2)
plt.figure(figsize=(8, 8))
plt.imshow(img_rgb_copy)
plt.show()