# Class
# __init__() # 인스턴스 생성자
# __new__() # 클래스 생성자
# 인스턴스 메소드는 항상 self 매개변수를 포함해야 함
class Car:
# 인스턴스 생성자
def __init__(self):
# 인스턴스 변수들
self.color = 0xFF0000
self.wheel_size = 16
self.displacement = 2000
def forward(self):
print('call car.forward()')
def backward(self):
print('call car.backward()')
def turn_left(self):
print('call car.turn_left()')
def turn_right(self):
print('call car.turn_right()')
if __name__ == '__main__':
my_car = Car()
print('0x{:02X}'.format(my_car.color))
print(my_car.wheel_size)
print(my_car.displacement)
my_car.forward()
my_car.backward()
my_car.turn_left()
my_car.turn_right()
class ClassVar:
# 클래스 변수
text_list = [] # 여러 인스턴스에서 함께 접근이 가능함
def add(self, text):
self.text_list.append(text)
def print_list(self):
print(self.text_list)
if __name__ == '__main__':
a = ClassVar()
a.add('a')
a.print_list() # ['a'] 출력을 기대함
b = ClassVar()
b.add('b')
b.print_list() # ['b'] 출력을 기대하나 실제 ['a', 'b'] 가 출력됨
class InstanceVar:
def __init__(self):
self.text_list = []
def add(self, text):
self.text_list.append(text)
def print_list(self):
print(self.text_list)
if __name__ == '__main__':
a = InstanceVar()
a.add('a')
a.print_list() # ['a'] 출력을 기대함
b = InstanceVar()
b.add('b')
b.print_list() # ['b'] 출력을 기대한 것 처럼 실제 ['b'] 가 출력됨
class ContactInfo:
# 인스턴스 생성자 지정시 self 외에 추가로 매개변수를 지정 가능함
def __init__(self, name, email):
self.name = name
self.email = email
def print_info(self):
print('{0} : {1}'.format(self.name, self.email))
if __name__ == '__main__':
md = ContactInfo('명덕','email')
md2 = ContactInfo('명덕2','email2')
md.print_info()
md2.print_info()
# 클래스에 속한 메소드로
# 정적 메소드(Static Method) @staticmethod
# 정적 메소드는 self 매개변수를 전달 받을 방법이 없음.
# 객체/인스턴스의 변수에 접근할 수 없음. 정적 메소드는 객체의 데이터 속성과 관계가 없는 코드로 구현되는 것이 일반적임
# 클래스 메소드(Class Method) @classmethod
# cls 를 통해 클래스 자체를 전달
# 인스턴스 메소드(Instance Method) #데코레이터 없음
# self를 통해 해당 인스턴스 자체를 전달
class Calculator:
@staticmethod
def plus(a, b):
return a + b
@staticmethod
def minus(a, b):
return a - b
@staticmethod
def multiply(a, b):
return a * b
@staticmethod
def divide(a, b):
return a / b
if __name__ == '__main__':
print('{0} + {1} = {2}'.format(7, 4, Calculator.plus(7, 4)))
print('{0} - {1} = {2}'.format(7, 4, Calculator.minus(7, 4)))
print('{0} * {1} = {2}'.format(7, 4, Calculator.multiply(7, 4)))
print('{0} / {1} = {2}'.format(7, 4, Calculator.divide(7, 4)))
class InstanceCounter:
count = 0
def __init__(self):
InstanceCounter.count += 1
@classmethod # 클래스 메소드를 정의하기 위해 @classmethod 데코레이터를 앞에 붙임
def print_instance_count(cls): # 메소드의 매개변수를 하나 이상 정의함 cls는 클래스를 나타내는 필수 매개변수
print(cls.count)
if __name__ == '__main__':
a = InstanceCounter()
InstanceCounter.print_instance_count()
b = InstanceCounter()
InstanceCounter.print_instance_count()
c = InstanceCounter()
InstanceCounter.print_instance_count()
# Private member
# 1. 두 개의 밑줄 __ 이 접두사여야 함. 예) __number
# 2. 접미사는 밑줄이 한 개까지만 허용됨. 예) __number_
# 3. 접미사의 밑줄이 두 개 이상이면 퍼블릭 멤버로 간주함. 예) __number__
class HasPrivate:
def __init__(self):
self.public = 'public'
self.__private = 'private'
def print_from_internal(self):
print(self.public)
print(self.__private)
if __name__ == '__main__':
obj = HasPrivate()
obj.print_from_internal()
print(obj.public)
# print(obj.__private) # 오류 발생
# AttributeError: 'HasPrivate' object has no attribute '__private'
# 상속(Inheritance)
# class 기반클래스:
# # 멤버 정의
# class 파생클래스(기반클래스):
# # 아무 멤버를 정의하지 않아도 기반클래스의 모든 것을 상속 받음
# # 단, Private member(__로 시작되는)는 제외
class Base:
def base_method(self):
print('base_method')
class Derived(Base):
pass
if __name__ == '__main__':
base = Base()
base.base_method()
derived = Derived()
derived.base_method()
# 기반클래스의 명시적 생성자(__init__) 호출
# 모든 클래스는 object의 파생클래스임
# super()는 기반클래스의 객체 역할을 하는 프록시(Proxy)를 반환하는 내장 함수
class A:
def __init__(self):
print('A.__init__()')
self.message = 'Hello'
class B(A):
def __init__(self):
#A.__init__(self) # B 클래스 안에서 A 클래스의 __init__() 메소드를 호출
super().__init__() # 위 코드와 동일한 결과
print('B.__init__()')
if __name__ == '__main__':
obj = B()
obj.message # error 발생
# AttributeError: 'B' object has no attribute 'message'
# 기대와는 다르게 A.__init__ 은 호출 되지 않음
# 파이썬은 암묵적(Implicit)인 것을 실헝하고 명시적인 것을 선호함
# 따라서 위에 A.__init__(self) 메소드를 호출해야 함
# super() 없이 상위 클래스의 __init__() 메소드를 호출하는 경우
# 기반 클래스의 __init__() 메소드가 호출됨
class Base:
def __init__(self):
print('Base')
class Derived(Base):
pass
if __name__ == '__main__':
d = Derived()
# 다중 상속
class A:
def method(self):
print('A')
class B(A):
def method(self):
print('B')
class C(A):
def method(self):
print('C')
class D(B, C):
pass
class E(C, B):
pass
if __name__ == '__main__':
obj = D()
obj.method() # 다중 상속의 문제 (다이아몬드 형태의 상속)
# B, C 클래스가 A 클래스를 상속 받아 method() 메소드를 오버라이딩(Overriding) 하고
# D 클래스가 B, C의 클래스를 다중 상속 받아 method() 메소드가 겹쳐지는 문제가 발생할 때
# 기반 클래스 목록에서 먼저 선언된 (B가 C보다 먼저 선언됨) B 클래스의 method()를 상속받음
# 오버라이딩(Overriding)은 기반 클래스로부터 상속받은 메소드를 다시 정의하는 것
obj2 = E()
obj2.method()
# 오버라이딩되기 이전의 기반 클래스의 메소드를 호출하는 경우
class Car:
def ride(self):
print('Run')
class FlyingCar(Car):
def ride(self):
super().ride() # super()를 통해 기반 클래스의 메소드를 호출함
print("Fly")
my_car = FlyingCar()
my_car.ride()
# 데코레이터: 함수를 꾸미는 객체
# __call__ 는 객체를 함수 호출 방식으로 사용하게 만드는 특별 메소드
class Callable:
def __call__(self):
print('I am Called.')
if __name__ == '__main__':
obj = Callable()
obj()
class MyDecorator:
# __init__() 메소드의 매개변수를 통해 함수를 받아들이고 데이터 속성에 저장함
def __init__(self, f):
print('Initializing MyDecorator...')
self.func = f
def __call__(self):
print('Begin :{0}'.format(self.func.__name__))
# __call__() 메소드가 호출되면 생성자에서 저장해둔 함수(데이터 속성)를 호출함
self.func()
print('End :{0}'.format(self.func.__name__))
# 데코레이터를 사용하는 방법 1: 생성자
def print_hello():
print('Hello')
print_hello = MyDecorator(print_hello)
print_hello()
# 데코레이터를 사용하는 방법 2: @기호
@MyDecorator
def print_hello2():
print('Hello')
print_hello2()
# 생성자 방법과 @기호 방법은 기능적으로 완전히 똑같이 동작함
# for문으로 list를 순회하는 예제
list = [1, 2, 3, 4]
for e in list:
print(e)
print('--')
for i in range(3):
print(i)
print('--')
iterator = range(3).__iter__()
print(iterator.__next__()) # 0
print(iterator.__next__()) # 1
print(iterator.__next__()) # 2
#print(iterator.__next__()) # error 발생, StopIteration 예외 발생
# range()는 __iter__() 메소드를 구현하는 순회가능한 객체를 반환하는 함수
# for문으로 순회 가능(Iterable)한 객체 생성
class MyRange:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.current < self.end:
current = self.current
self.current += 1
return current
else:
raise StopIteration()
for i in MyRange(0, 5):
print(i)
# 제네레이터(Generator)는 이터레이터(Iterator)처럼 동작하는 함수
# Generator는 클래스를 정의하지 않아도 되고, __iter__(), __next__() 메소드를 구현할 필요 없음
# 다만, yield 문을 이용해 값을 반환하면 됨
# yield문은 return문 처럼 함수를 실행하다가 값을 반환하지만, return문 처럼 함수를 종료시키지 않고 중단시켜 놓기만 함
def generator():
yield 0
yield 1
yield 2
yield 3
yield 4
iterator = generator()
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
# print(iterator.__next__()) # error 발생
for i in generator():
print(i)
def YourRange(start, end):
current = start
while current < end:
yield current
current += 1
return
for i in YourRange(0, 5):
print(i)
# 추상 기반 클래스(Abstract Base Class)는 파생 클래스가 갖춰야 할 특징(메소드)을 강제하는 기능을 함
# 추상 클래스를 정의할 때는 abc 모듈의 ABCMeta 클래스와 @abstractmethod 데코레이터를 이용함
# 메타 클래스는 클래스에 대한 정보를 갖고 있는 클래스를 말함
# ABCMeta 클래스는 클래스가 특정 메소드를 구현하는지를 테스트하는 기능을 갖고 있음
from abc import ABCMeta
from abc import abstractmethod
class AbstractDuck(metaclass = ABCMeta):
@abstractmethod
def Quack(self):
pass
#class Duck(AbstractDuck):
# pass
#duck = Duck() # error 발생
# TypeError: Can't instantiate abstract class Duck with abstract methods Quack
# AbstractDuck를 상속 받는 파생 클래스인 Duck은 Quack() 메소드를 반드시 구현해야 함
class Duck(AbstractDuck):
def Quack(self):
print('[Duck] Quack')
duck = Duck()
duck.Quack()
# 예외처리 try ~ except ~ else ~ finally
# 예외발생 raise
def my_power(y):
print("숫자를 입력하세요.")
x = input()
return int(x) ** y
my_power(2) # a 입력 시 ValueError: invalid literal for int() with base 10: 'a'
my_list = [1, 2, 3]
try:
print('첨자를 입력하세요.')
index = int(input())
print(my_list[index]/0)
except ZeroDivisionError as err: # 0으로 나눌 때 예외 발생 시
print('0으로 나눌 수 없습니다. ({0})'.format(err))
except IndexError as err: # 인덱스 예외 발생 시
print('잘못된 첨자입니다. ({0})'.format(err))
except : # 앞서 정의 된 예외 발생 외 모든 예외 처리
print('예외가 발생했습니다.')
my_list = [1, 2, 3]
try:
print('첨자를 입력하세요')
index = int(input())
print("my-list[{0}]: {1}".format(index, my_list[index]))
except Exception as err:
print("예외가 발생했습니다. ({0})".format(err))
else :
print("리스트의 요소 출력에 성공하였습니다.")
finally:
print("마지막에 무조건 실행됩니다.")
try:
raise Exception("예외를 발생시킴")
except:
print('예외가 일어남')
def some_function():
print("1~10 사이의 수를 입력하세요:")
num = int(input())
if num < 1 or num > 10:
raise Exception("유효하지 않은 숫자입니다.: {0}".format(num))
else:
print("입력한 수는 {0}입니다.".format(num))
try:
some_function()
except Exception as err:
print("예외가 발생했습니다. {0}".format(err))
# 발생된 예외처리를 상위 호출자에게 전달
def some_function():
print("1~10 사이의 수를 입력하세요:")
num = int(input())
if num < 1 or num > 10:
raise Exception("유효하지 않은 숫자입니다.: {0}".format(num)) # -1- : 예외처리 발생
else:
print("입력한 수는 {0}입니다.".format(num))
def some_function_caller():
try:
some_function()
except Exception as err: # -2- : -1-에서 발생시킨 예외를 받아서 처리함
print("1) 예외가 발생했습니다. {0}".format(err))
raise # -3- : 앞서 받은 예외를 그대로 다시 발생
try:
some_function_caller()
except Exception as err: # -4- : -3-에서 발생시킨 예외를 받아서 처리함
print("2) 예외가 발생했습니다. {0}".format(err))
# 사용자 정의 예외 형식
class MyException(Exception):
def __init__(self):
super().__init__("MyException이 발생했습니다.")
# raise MyException() # MyException: MyException이 발생했습니다.
# 문자열을 정수로 변환하는 convert_to_integer() 함수가 매개변수를 확인하여
# 자신이 처리할 수 없는 문자가 들어 있으면 사용자 정의 예외인 InvalidIntException()을 일으키는 코드
class InvalidIntException(Exception):
def __init__(self, arg):
super().__init__('정수가 아닙니다. {0}'.format(arg))
def convert_to_integer(text):
if text.isdigit(): # 부호(+, -) 처리 못함
return int(text)
else:
raise InvalidIntException(text)
if __name__ == '__main__':
try:
print('숫자를 입력하세요:')
text = input()
number = convert_to_integer(text)
except InvalidIntException as err:
print('예외가 발생했습니다 ({0})'.format(err))
else:
print('정수 형식으로 변환되었습니다 : {0}({1})'.format(number, type(number)))
my_list = [1, 2, 3, 4, 5]
def print_element(arg, index):
try:
print(arg[index])
except IndexError as err:
print("유효한 인덱스 범위를 벗어났습니다. {0}".format(err))
print_element(my_list, 2)
print_element(my_list, 4)
print_element(my_list, 5)
# 파일 처리 : 열기 -> 읽기/쓰기 -> 닫기
# file = open()
# file.read() / file.write()
# file.close()
file = open('test.txt', 'w')
file.write('Hello')
file.close()
file = open('test.txt', 'r')
str = file.read()
print(str)
file.close()
# 자원 누수 방지 with ~ as
with open('test.txt', 'r') as file: # __enter__() 호출
str = file.read()
print(str) # 마지막 라인에서 __exit__() 호출
#file.close() # 생략해도 컨텍스트 매니저(Context Manager)를 통해 블록을 관리함
# 컨텍스트 매니저는 __enter__()와 __exit__() 메소드를 구현함
class open2(object):
def __init__(self, path):
print('initialized')
self.file = open(path)
def __enter__(self):
print('entered')
return self.file
def __exit__(self, ext, exv, trb):
print('exited')
self.file.close()
return True
with open2("test.txt") as file:
s = file.read()
print(s)
# 컨텍스트 매니저를 구현하기 위한 클래스
# @contextmanager 데코레이터
from contextlib import contextmanager # contextlib 모듈로부터 contextmanager를 반입
@contextmanager # @contextmanager 데코레이터로 함수 수식
def 함수이름():
# 자원 획득
try:
yield 자원 # yield문을 통해 지원 반환 : with문의 코드블록이 시작될 때 실행됨
finally:
# 자원 해제 # with문의 코드블록이 종료될 때 실행됨
# @contextmanager 데코레이터 예제
from contextlib import contextmanager
@contextmanager
def open3(path):
print('opening file...')
file = open(path)
try:
print('yielding file...')
yield file
finally:
print('closing file...')
file.close()
with open3("test.txt") as file:
s = file.read()
print(s)
# open 함수의 8개 매개변수
# open(file, mode='r', buffering=-1. encoding=None, errors=None, newline=None, closefd=True, opener=None)
# mode - 파일 접근 모드 설정 (가본값은 'rt'임)
# 'r' = 읽기용(기본값) / 'w' = 쓰기용 / 'x' = 배타적 생성모드로 열기, 파일이 존재하면 IOError 예외발생 /
# 'a' = 쓰기용, 단 'w'와는 다르게 기존에 파일이 존재하는 경우 기존 내용에 덧붙임 /
# 'b' = 바이너리 모드 / 't' = 텍스트 모드(기본값) / '+' = 읽기/쓰기용으로 파일 읽기
# buffering - 버퍼링 모드 (기본값은 -1)
# 0 - 버퍼링 미수행 - 바이너리 모드에서만 사용 가능
# 1 - 개행 문자(\n)를 만날 때까지 버퍼링하는 라인 버퍼링 수행 - 텍스트 모드에서만 사용 가능
# 2 - 임의의 값으로 버퍼의 크기를 직접지정하고 싶을 때는 1보다 큰수를 입력
# encoding - 텍스트 인코딩
# 파이썬 지원 인코딩 - https://docs.python.org/3/library/codecs.html#standard-encodings
# errors - encoding 매개변수와 관련하여 문자열 인코딩과 디코딩 수행시 발생하는 에러처리 방법 설정
# 'strict' - 인코딩 에러가 발생할 때 ValueError 예외를 발생, None과 똑같은 효과
# 'ignore' - 에러 무시
# 'replace' - 기형적인 데이터가 있는 경우 대체 기호(?)를 삽입
# 'surrogateescape' - U+DC80 ~ U+DCFF 사이에 있는 유니코드 사용자 자유 영역의 잘못된 바이트를 코드 포인트로 나타냄
# 'xmlcharrefreplace' - 파일에 기록하려는 텍스트 안에서 지정된 인코딩에서 지원되지 않는 문자를 &#NNN; 꼴의 XML 문자 참조로 바꿔 기록, 쓰기만
# 'backslashreplace' - 파일에 기록하려는 텍스트 안에서 지정된 인코딩에서 지원되지 않는 문자를 역슬래시(\)로 시작되는 이스케이프 시퀀스로 바궈 기록, 쓰기만
# newline - 파일 읽고 쓸 때 줄바꿈을 어떻게 처리할지를 나타냄
# None, '', '\n', '\r', '\r\n' 중 하나를 입력
# closefd - file 매개변수에 파일 경로가 아닌 파일 기술자가 입력되었을 때 사용됨
# opener - 파일을 여는 함수를 직접 구현하고자 할 때 사용
import os
os.linesep # 현재 시스템이 지원하는 개행 문자
# 문자열을 담은 리스트를 파일에 쓰는 write() 메소드
lines = ["We'll find a way we always have - Interstellar\n",
"I'll find you and I'll kill you - Take\n",
"I'll be back - Terminator 2\n"]
with open('movie_quotes.txt', 'w') as file:
for line in lines:
file.write(line) # 각 줄 마다 쓰기
# 문자열을 담은 리스트를 파일에 쓰는 writelines() 메소드
lines = ["We'll find a way we always have - Interstellar\n",
"I'll find you and I'll kill you - Take\n",
"I'll be back - Terminator 2\n"]
with open('movie_quotes.txt', 'w') as file:
file.writelines(lines) # 모든 줄을 한꺼번에 쓰기
# 줄 단위로 텍스트를 읽는 readline() 메소드
with open('movie_quotes.txt', 'r') as file:
line = file.readline() # 한 줄 씩 읽기
while line != '': # readline() 메소드는 파일의 끝에 도달하면 ''을 반환함, 빈줄의 경우 개행 문자를 반환함
print(line, end='')
line = file.readline()
# 줄 단위로 텍스트를 읽는 readlines() 메소드
with open('movie_quotes.txt', 'r') as file:
lines = file.readlines() # 모든 줄 읽기
#line = ''
for line in lines:
print(line, end='')
lines = ['안녕하세요?\n',
'Hello\n']
with open('greetings_utf8.txt', 'w', encoding='utf-8') as file:
for line in lines:
file.write(line)
with open('greetings_utf8.txt', 'r', encoding='utf-8') as file:
lines = file.readlines()
for line in lines:
print(line, end = '')
# 한글 버전 윈도우8/윈도우10의 명령 프롬프트의 기본 인코딩은 CP949임
# 유니코드 문서를 강제로 ascii 인코딩으로 읽는 예제
with open('greetings_utf8.txt', 'r', encoding='ascii', errors='ignore') as file:
lines = file.readlines()
line = ''
for line in lines:
print(line)
# 바이너리 파일 처리 - struct 모듈 이용
import struct
packed = struct.pack('i', 123) # 'i'에 따라 4바이트 크기의 bytes 객체를 packed에 준비하고 123 값을 복사함
for b in packed:
print(b)
unpacked = struct.unpack('i', packed) # 튜플 형식을 반환
unpacked
type(unpacked)
# struct.pack(fmt, v1, v2, ...) # 데이터 -> bytes
# struct.unpack(fmt, buffer) # bytes -> 튜플(데이터)
# pack과 unpack의 형식문자열(fmt) pp.262~264 참고
# 예를 들어 =2f12si 의 경우, 바이트 순서(=)는 시스템 바이트 순서를 따르며,
# 4바이트 부동소수형 2개(2f), 크기가 12인 bytes형(12s), 4바이트 부호있는 정수형 1개(i)로 이루어진 구조를 나타냄
# Ref. https://docs.python.org/3/library/struct.html#format-strings
import struct
packed = struct.pack('f', 123.456) # float
unpacked = struct.unpack('f', packed)
print(unpacked) # (123.45600128173828,)
packed = struct.pack('12s', '빨간당무'.encode()) # 12 bytes
unpacked = struct.unpack('12s', packed)
print(unpacked) # (b'\xeb\xb9\xa8\xea\xb0\x84\xeb\x8b\xb9\xeb\xac\xb4',)
packed = struct.pack('2d2i', *(123.456, 987.765, 123, 456)) # double x2, integer x2
# *연산자가 튜플이나 리스트의 요소를 하나씩 불리해서 매개변수로 입력시켜줌
unpacked = struct.unpack('2d2i', packed)
print(unpacked) # (123.456, 987.765, 123, 456)
# 바이너리 데이터 쓰기 예제
import struct
struct_fmt = '=16s2fi' # char[16], float[2], int
city_info = [
# CITY, Latitude, Longitude, Population
('서울'.encode(encoding='utf-8'), 37.566535, 126.977969, 9820000),
]
with open('cities.dat', 'wb') as file:
for city in city_info:
file.write(struct.pack(struct_fmt, *city))
# 바이너리 데이터 읽기 예제
import struct
struct_fmt = '=16s2fi' # char[16], float[2], int
struct_len = struct.calcsize(struct_fmt)
cities = []
with open('cities.dat', 'rb') as file:
while True:
buffer = file.read(struct_len)
if not buffer: break
city = struct.unpack(struct_fmt, buffer)
cities.append(city)
for city in cities:
name = city[0].decode(encoding='utf-8').replace('\x00', '')
# pack()하는 과정에서 문자를 할당하고 남은 공간에 채워진 \x00를 디코딩한 후 빈 문자열로 다시 바꿔 넣음
print('City:{0}, Lat/Long:{1}/{2}, Population:{3}'.format(name, city[1], city[2], city[3]))
'Study > Programming' 카테고리의 다른 글
[파이썬 Python] glob.glob로 가져올 때 정렬(sort)하기 (1) | 2018.04.09 |
---|---|
[파이썬 Python] 파일 읽을 때 feff 문제 (1) | 2017.10.11 |
Anaconda 4.4.0 (python 3.6) + KoNLPy 설치 (5) | 2017.09.03 |
Python 요약 (0) | 2017.07.16 |
특정 날짜로 요일 계산하는 공식 (0) | 2015.06.03 |