Python
Python에서는 모든 것이 객체다
함수도 객체 파일도 객체 가능한 모든 것들이 객체
Object (type)의 내부 정보를 알고 싶을 때
1. type 2. dir 3. id 4. vars
이름/식별자를 불렀을 때 내부적으로 작동하는 것들
1. REPR 2. STR
class A:
def __repr__(self):
return 'REPR'
def __str__(self):
return 'STR'
a = A()
a # 이름을 부르면 __repr__가 호출된다
# REPR
print(a) # 이름을 print하면 __str__이 호출된다 / escape를 처리해준다
# STR
※ self를 붙이는 이유
class A:
def __init__(this): # self 대신 다른 것 사용 가능 그러나 pep8에서 self 사용 권장
print('a')
def __call__(self): # 객체 지향에서 self는 인스턴스(object)를 뜻한다
print('call')
def aa(self):
print('aa')
# python 내부에서 c기반으로 작동하기 때문에 (c는 method 개념이 없다) 이와 같이 만들어 졌다
a = A()
A.aa(a) # 어떤 인스턴스에 대해서 사용할 것인가 인자가 필요 / version 1 / 주체가 class A
a.aa(a) # 인스턴스가 주체이고 싶을 때 / argument가 중복되기 때문에 a 생략하게 만들었다
a.aa()
import itertools
dir(itertools) #__package__ / dir은 객체의 모든 attribute를 조회 함수이다
['__doc__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'_grouper',
'_tee',
'_tee_dataobject',
'accumulate',
'chain',
'combinations',
'combinations_with_replacement',
'compress',
'count',
'cycle',
'dropwhile',
'filterfalse',
'groupby',
'islice',
'permutations',
'product',
'repeat',
'starmap',
'takewhile',
'tee',
'zip_longest']
type(itertools) # module이라는 데이터 타입
# module
id(itertools)
# 140663255600208
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__',
'bit_length',
'conjugate',
'denominator',
'from_bytes',
'imag',
'numerator',
'real',
'to_bytes']
객체 지향
[객체지향의 4가지 특성]
1. 캡슐화
- 실제 구현내용을 감추는 것
- 재활용 가능
- 파이썬에서는 기본적으로 외부에서 클래스 접근 가능
- descriptor로 클래스 접근을 막을 수도 있다
2. 추상화
- 필요로 하는 속성이나 행동을 추출하는 작업
- 구체적인것과 추상적인 것을 분리시킨다
- 특징을 뽑아 객체로 구현
3. 상속
- 추상화의 반대
- 추상화한 클래스를 물려받아 구체적으로 원하는 대로 바꾸어 사용 가능
4. 다형성
- 다양한 결과를 낼 수 있다
Subclass(Inheritance)
'장점'
- 부모 클래스의 기능을 재사용
-부모의 기능을 그대로 사용한다
- 부모의 기능을 일부만 사용한다
- 부모에게 없는 기능을 추가 가능하다
'단점'
- 부모가 바뀌면 같이 바뀐다
# composition 방식으로 inheritance 방식 대체 가능하다
※ duck typing, composition으로 사용해도 상속받은 것과 유사하게 사용 가능하다
class A:
a = 1
class B(A): # Delegat(위임/대리자)
pass
id(A.a) == id(B.a)
# True
A.a is B.a # B에 없으면 부모의 것을 불러오기 때문에 같아진다
# True
Python의 모든 객체는 object로 부터 상속 받는다
class A(object, metaclass=type):
pass
dir(A)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__']
dir(A.__class__)
['__abstractmethods__',
'__base__',
'__bases__',
'__basicsize__',
'__call__',
'__class__',
'__delattr__',
'__dict__',
'__dictoffset__',
'__dir__',
'__doc__',
'__eq__',
'__flags__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__instancecheck__',
'__itemsize__',
'__le__',
'__lt__',
'__module__',
'__mro__',
'__name__',
'__ne__',
'__new__',
'__prepare__',
'__qualname__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasscheck__',
'__subclasses__',
'__subclasshook__',
'__text_signature__',
'__weakrefoffset__',
'mro']
다중 상속
다중 상속이란 2개 이상 클래스를 상속하는 것을 말한다
python은 다중 상속을 지원하는 언어이다
다중 상속은 편한 기능이지만 다이아몬드 문제가 발생할 수 있다
단일 상속인 프로그래밍 언어들이 많음(Java)
class A:
x = 1
class B:
x = 2
class C(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
다이아몬드 문제
class A:
pass
class B(A):
pass
class C(A):
pass
class D(A, B):
pass
# 이런 경우 메소드의 실행순서를 정할 수 없다
# TypeError: Cannot create a consistent method resolution order (MRO) for bases A, B
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
D.mro() # linearization / tail recursion elimination => linearization
# [__main__.D, __main__.B, __main__.C, __main__.A, object]
dir(D) # metaclass
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__']
MRO (Method Resolution Order)
메소드 실행 순서를 확인하는 클래스 메소드(인스턴스로 사용 불가)
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self): #overriding (parent와 가능한 parameter 일치)
A.__init__(self)
print('B')
class C(A):
def __init__(self):
A.__init__(self)
print('C')
class D(B, C):
def __init__(self):
B.__init__(self) # __init__ 함수
C.__init__(self)
print('D')
d = D() # A가 중복해서 실행되는 문제가 발생한다
# A
# B
# A
# C
# D
D.mro()
# [__main__.D, __main__.B, __main__.C, __main__.A, object]
import tensorflow as tf
model = tf.keras.models.Sequential()
model.__class__.mro()
[keras.engine.sequential.Sequential,
keras.engine.functional.Functional,
keras.engine.training.Model,
keras.engine.base_layer.Layer,
tensorflow.python.module.module.Module,
tensorflow.python.training.tracking.tracking.AutoTrackable,
tensorflow.python.training.tracking.base.Trackable,
keras.utils.version_utils.LayerVersionSelector,
keras.utils.version_utils.ModelVersionSelector,
object]
Super - 중복 실행을 방지하는 방법
super는 상속을 전부 실행하지 않는다
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
super().__init__() #super()는 부모의 인스턴스다 / python3 방식이다
print('B')
class C(A):
def __init__(self):
super(C, self).__init__() # __init__은 메소드 이다 / python2, python3 방식이다
print('C')
class D(B, C):
def __init__(self):
super().__init__()
print('D')
d = D()
# A
# C
# B
# D
D.mro()
# [__main__.D, __main__.B, __main__.C, __main__.A, object]
실행 순서는 D -> B -> C -> A 인데 출력 결과는 왜 반대일까? 그 이유는 바로 super사용시 stack에 들어가기 때문이다
※ Stackoverflow
def fib(n):
return fib(n-1) + fib(n-2) if n>2 else 1 # 재귀적으로 계산되는 중간 과정은 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.30000000000000004
1.7976931348623157e+308 == 1.7976931348623157e+308 + 1 # 근사적으로 계산하기 때문에 속도가 빠르다
# True
a == a + 1 # infinity
Duck Typing
미운오리새끼 이야기에서 유래가 되어 오리가 아닌데 오리처럼 행동을 하면 오리라고 간주한다는 개념이다
타입을 미리 정하지 않고 실행되었을 때 해당 Method들을 확인하여 타입을 정한다
'장점'
- 타입에 대해 자유롭다
- 상속을 하지 않아도 상속을 한것처럼 클래스의 메소드 사용이 가능하다
'단점'
- 원치 않는 타입이 들어 갈 경우 오류가 발생할 수 있다
- 오류 발생시 원인을 찾기 어려울수 있다
- 호환성 떨어짐 => 추상 클래스로 대체
- 코딩 많이 해야 함
Composition
상속을 하지 않고 클래스내에 객체를 불러와 다른 클래스의 일부 기능을 사용하는 방법.
상속의 위험부담을 줄일 수 있다
class SecurityDoor:
locked = True
def __init__(self, number, status):
self.door = Door(number, status) # Door의 객체를 갖게 한다
def open(self):
if self.locked:
return
self.door.open()
def __getattr__(self, attr): # try except와 비슷
return getattr(self.door, attr) # Door의 attr를 가져와라 (상속을 비슷하게 사용)
class ComposedDoor:
def __init__(self, number, status):
self.door = Door(number, status)
def __getattr__(self, attr): # 없으면 가져와라
return getattr(self.door, attr) # 바꾸지 않고 불러와서 사용할 때
Meta class
type => 모든 클래스의 행동을 결정해준다 클래스의 행동을 바꾸고자 할때 사용하는 클래스
type('int2', (int,), {}) # __main__ 메소드가 있다면 현재 내 작업 공간에서 만든 것이라는 의미이다
# __main__.int2
a = type('int2', (int,), {})
type(a)
# type
class A: # attribute(클래스안에 정의된 모든 것) vs property (descriptor)
pass
%whos # 현재 작업 공간에 어떤 객체가 있는가 확인 할때 사용
#
Variable Type Data/Info
-------------------------------
A type <class '__main__.A'>
a type <class '__main__.int2'>
drive module <module 'google.colab.dri<...>s/google/colab/drive.py'>
itertools module <module 'itertools' (built-in)>
%who_ls
['A', 'a', 'drive', 'itertools']
%lsmagic
Available line magics:
%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'
class A:
t = 1
def tt(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
- def x(*b): # 인자의 갯수 제한을 두지 않는다 return b
5. parameter *
- def name(*,a,b): # keyword only *다음엔 keyword를 사용해야 한다
return a + b # positional 방식 다음에 keyword 방식을 써야 한다
6. parameter **
- def y(**b): # Variable Keyword return b 7. argument *
- def a(*b):
return b x = [1,2,3,4] a(*x) # argument unpacking
8. argument **
- def aa(**b):
return b y = {'a': 1, 'b' : 2} aa(**)
9. import에서 모두
- import *
※ def t(a, *b)이런 형태를 자주 쓰는 이유
def t(*a, **b):
print(a)
print(b)
# parameter, argument를 정확히 맞출 필요가 없음, 인터페이스의 유연성을 위해
def aa(**b):
return b
y= {'a':1,'b':2}
z= {'c':2,'a':3}
{**y, **z}
# {'a': 3, 'b': 2, 'c': 2}