본문 바로가기
Web & Mobile/Python

Lecture 84 - Python(5) 클래스와 객체, 모듈

by Bennyziio 2019. 7. 25.
반응형

클래스

클래스 구조 만들기

객체에 숫자 지정할 수 있게 만들기

'''
Created on 2018. 9. 14.

@author: kitcoop
'''
# 함수(function)
def func1():
	print('func1() 호출')

def func2(first):
	print('func2() 호출 : {0}'.format(first))
	
class FourCal :
	# 메서드
	def cfunc1(self):
		print('cfunc1() 호출')
		# self = this
		print(self)
		
	def cfunc2(self, first):
		print('cfunc2() 호출 : {0}'.format(first))
		
a = FourCal()
print(type(a))

func1()
a.cfunc1()

func2(10)
a.cfunc2(20)

java와 비교해보면 self 는 this이다.

class FourCal :
	# 클래스 변수
	# java에서 static
	# 멤버 변수
	# java에서 멤버 변수로 접근하려면 this.멤버변수로 접근했다
	# 메서드
	def cfunc1(self):
		# 멤버변수 선언
		self.data1 = 1
		print(self.data1)
		
fc = FourCal()
fc.cfunc1()

class FourCal :
	# 클래스 변수
	# java에서 static
	# 멤버 변수
	# java에서 멤버 변수로 접근하려면 this.멤버변수로 접근했다
	# 메서드
	def cfunc1(self):
		# 멤버변수 선언
		self.data1 = 1
		print(self.data1)
	
	def cfunc2(self):
		print(self.data1)
		
fc = FourCal()
fc.cfunc1()
fc.cfunc2()

위와 같은 식이면 cfunc2()는 멤버변수라면 값이 불러와지고 지역변수라면 안될 것이다 근데 결과는 1이 출력되었기때문에 멤버변수임을 알 수 있다. 허나 fc.cfunc1()가 실행되지 않으면 에러가 난다.

class FourCal :
	# 클래스 변수
	# java에서 static
	# 멤버 변수
	# java에서 멤버 변수로 접근하려면 this.멤버변수로 접근했다
	# 메서드
	def cfunc1(self):
		# 멤버변수 선언
		self.data1 = 1
		print(self.data1)
	
	def cfunc2(self):
		print(self.data1)
		
fc = FourCal()
# fc.cfunc1()
fc.cfunc2()

더하기 기능 만들기

class FourCal():
	def setdata(self, first, second):
		self.first = first
		self.second = second
	def sum(self):
		result = self.first + self.second
		return result

a = FourCal()
a.setdata(4, 2)

print(a.sum())

class FourCal():
	def setdata(self, first, second):
		self.first = first
		self.second = second
	def sum(self):
		result = self.first + self.second
		return result

a = FourCal()
# a.setdata(4, 2)
FourCal.setdata(a, 4, 2)

print(a.sum())

eval() - 실행 함수로 해보자

class FourCal():
	def setdata(self, first, second):
		self.first = first
		self.second = second
	def sum(self):
		result = self.first + self.second
		return result

a = FourCal()
# a.setdata(4, 2)
# FourCal.setdata(a, 4, 2)
eval('FourCal.setdata(a, 4, 2)')

print(a.sum())

지금까지 사용한 소스에서 setdata, getdata등은 setter, getter등으로 기존 프로그래머들이 사용하였기 때문에 비슷하게 구현해 준 것이다.

생성자 (Constructor) - 생성자는 초기화를 자동으로 하는 특성을 가지고 있다.

class FourCal():
	def __init__(self):
		self.first = 10
		self.second = 20
	def setdata(self, first, second):
		self.first = first
		self.second = second
	def sum(self):
		result = self.first + self.second
		return result

a = FourCal()
# a.setdata(4, 2)
# FourCal.setdata(a, 4, 2)
# eval('FourCal.setdata(a, 4, 2)')

print(a.sum())

오버로딩은 아래와 같이 사용하는 방법이 있다.

class FourCal():
# 	def __init__(self, first):
# 		self.first = 10
# 		self.second = 20
		
	def __init__(self, first, second):
		self.first = first
		self.second = second
		
	def setdata(self, first, second):
		self.first = first
		self.second = second
	def sum(self):
		result = self.first + self.second
		return result

a = FourCal(100, 200)
# a.setdata(4, 2)
# FourCal.setdata(a, 4, 2)
# eval('FourCal.setdata(a, 4, 2)')

print(a.sum())

클래스 변수

class Family:
	lastname = "김"

# 인스턴스화 과정이 없다.
print(Family.lastname)

# 인스턴스화 과정을 거쳐보자
a = Family()
b = Family()

print(a.lastname)
print(b.lastname)

위치를 확인해 보자 - id() 사용

class Family:
	lastname = "김"

# 인스턴스화 과정이 없다.
print(Family.lastname)

# 인스턴스화 과정을 거쳐보자
a = Family()
b = Family()

print(a.lastname)
print(b.lastname)

print(id(Family.lastname))
print(id(a.lastname))
print(id(b.lastname))

같은 값("김")을 가져오므로 주소값이 같다.

클래스의 상속

class FourCal():
	def __init__(self, first, second):
		self.first = first
		self.second = second
	def setdata(self, first, second):
		self.first = first
		self.second = second
	def sum(self):
		result = self.first + self.second
		return result
	def mul(self):
		result = self.first * self.second
		return result
	def sub(self):
		result = self.first - self.second
		return result
	def div(self):
		result = self.first / self.second
		return result

class MoreFourCal(FourCal):
	def pow(self):
		result = self.first ** self.second
		return result

mfc = MoreFourCal(4, 2)
print(mfc.sum())
print(mfc.pow())

메서드 오버라이딩 - 덮어쓰기

class FourCal():
	def __init__(self, first, second):
		self.first = first
		self.second = second
	def setdata(self, first, second):
		self.first = first
		self.second = second
	def sum(self):
		result = self.first + self.second
		return result
	def mul(self):
		result = self.first * self.second
		return result
	def sub(self):
		result = self.first - self.second
		return result
	def div(self):
		result = self.first / self.second
		return result

class MoreFourCal(FourCal):
	def pow(self):
		result = self.first ** self.second
		return result

fc = FourCal(4, 0)
print(fc.div())

위와 같이 실행하면 에러가 발생하였다. 0을 나눌 수 없기 때문이다.

class FourCal():
	def __init__(self, first, second):
		self.first = first
		self.second = second
	def setdata(self, first, second):
		self.first = first
		self.second = second
	def sum(self):
		result = self.first + self.second
		return result
	def mul(self):
		result = self.first * self.second
		return result
	def sub(self):
		result = self.first - self.second
		return result
	def div(self):
		result = self.first / self.second
		return result

class MoreFourCal(FourCal):
	def pow(self):
		result = self.first ** self.second
		return result
	
class SafeFourCal(FourCal):
	def div(self):
		if self.second == 0:
			return 0
		else:
			return self.first / self.second
	
# mfc = MoreFourCal(4, 2)
# print(mfc.sum())
# print(mfc.pow())

# fc = FourCal(4, 0)
# print(fc.div())

sfc = SafeFourCal(4, 0)
print(sfc.div())

클래스의 활용

결국 메소드로 처리하는것보단 클래스로 처리하는게 낫다라는 이야기

예외 처리
오류는 어떤 때 발생하는가?

자바와 같이 try catch를 사용한 것을 try except 구문을 사용한다

오류 예외 처리 기법
try, except 문

a = 4
b = 0

print(a / b)

a = 4
b = 0

# print(a / b)

print('시작')
try:
	print(a / b)
except ZeroDivisionError as e:
	print(e)
print('끝')

정상일 경우

a = 4
b = 1

# print(a / b)

print('시작')
try:
	print(a / b)
except ZeroDivisionError as e:
	print(e)
print('끝')

try .. else

print('시작')
try :
	f = open('foo.txt', 'r')
except FileNotFoundError as e:
	print(str(e))
else:
	data = f.read()
	f.close()
print('끝')

foo라는 파일이 있으면 foo파일 안에 적혀있는 데이터를 읽어온다.

print('시작')
try :
	f = open('foo.txt', 'r')
except FileNotFoundError as e:
	print(str(e))
else:
	data = f.read()
	print(data)
	f.close()
print('끝')

ex05.py를 읽어오고 싶었는데 인코딩이 안맞아서 에러가 났다. 인코딩을 맞춰주고 출력이 되게끔 해보자

import codecs

print('시작')
try :
	# utf-8을 읽을 때
	f = codecs.open('ex05.py', 'r', 'utf-8')
except FileNotFoundError as e:
	print(str(e))
else:
	data = f.read()
	print(data)
	f.close()
print('끝')

codec이라는 것을 import 시키고 f = codecs.open이라고 한뒤 반드시 utf-8로 설정해줘야 한다.

try .. finally - 무조건 수행

여러개의 오류처리하기

try:
	a = [1, 2]
	print(a[3])
# 	4/0
except ZeroDivisionError as e:
	print(e)
except IndexError as e:
	print(e)

try:
	a = [1, 2]
# 	print(a[3])
	4/0
except ZeroDivisionError as e:
	print(e)
except IndexError as e:
	print(e)

try:
	a = [1, 2]
	print(a[3])
	4/0
# except ZeroDivisionError as e:
# 	print(e)
# except IndexError as e:
# 	print(e)
except (ZeroDivisionError, IndexError) as e:
	print(e)

오류 회피하기

오류 일부러 발생시키기 - raise

예외 만들기 - 예외 클래스를 상속받아서 예외 발생

class MyError(Exception):
	pass

def say_nick(nick):
	if nick == '바보':
		raise MyError()
	print(nick)

say_nick('천사')
say_nick('바보')

class MyError(Exception):
	pass

def say_nick(nick):
	if nick == '바보':
		raise MyError()
	print(nick)

try:
	say_nick('천사')
	say_nick('바보')
except MyError:
	print('허용되지 않는 별명입니다.')

class MyError(Exception):
	pass

def say_nick(nick):
	if nick == '바보':
		raise MyError()
	print(nick)

try:
	say_nick('천사')
	say_nick('바보')
except MyError as e:
# 	print('허용되지 않는 별명입니다.')
	print(e)

class MyError(Exception):
	def __str__(self):
		return '허용되지 않는 별명입니다.'

def say_nick(nick):
	if nick == '바보':
		raise MyError()
	print(nick)

try:
	say_nick('천사')
	say_nick('바보')
except MyError as e:
# 	print('허용되지 않는 별명입니다.')
	print(e)

class MyError(Exception):
	def __init__(self, msg):
		self.msg = msg
		
	def __str__(self):
		return self.msg

def say_nick(nick):
	if nick == '바보':
		raise MyError('허용되지 않는 별명입니다.')
	print(nick)

try:
	say_nick('천사')
	say_nick('바보')
except MyError as e:
# 	print('허용되지 않는 별명입니다.')
	print(e)

에러 발생 시점에 오류메시지를 전달받았다.

모듈 - 라이브러리
모듈이란 함수나 변수 또는 클래스 들을 모아 놓은 파일이다. 모듈은 다른 파이썬 프로그램에서 불러와 사용할수 있게끔 만들어진 파이썬 파일이라고도 할 수 있다. 우리는 파이썬으로 프로그래밍을 할 때 굉장히 많은 모듈을 사용한다. 다른 사람들이 이미 만들어 놓은 모듈을 사용할 수도 있고 우리가 직접 만들어서 사용할 수도 있다. 여기서는 모듈을 어떻게 만들고 사용할 수 있는지 알아보겠다.

위 표시한 부분이 모듈(라이브러리)의 경로이다.

단순히 클래스라고 이름 짓는것이 아니라 모듈이라고 짓는다. 자바에서는 클래스는 하나의 파일이지만 파이선의 클래스는 더 다양한 요소들을 포함할 수 있기 때문에 자바 보다 큰 개념이다.

모듈 만들고 불러 보기

Ex03.mod1

def sum(a, b):
	return a + b

Ex03.exec1

# 파일명 = 모듈
import mod1
# 모듈 -> 클래스, 함수
print(mod1.sum(3, 4))

Ex03.mod1

def sum(a, b):
	return a + b

def safe_sum(a, b):
	if type(a) != type(b):
		print('더할수 있는 것이 아닙니다.')
		return
	else:
		result = sum(a, b)
	return result

Ex03.exec1

# 파일명 = 모듈
import mod1
# 모듈 -> 클래스, 함수
print(mod1.sum(10, 20))
print(mod1.safe_sum(3, 4))

Ex03.mod1

def sum(a, b):
	return a + b

def safe_sum(a, b):
	if type(a) != type(b):
		print('더할수 있는 것이 아닙니다.')
		return
	else:
		result = sum(a, b)
	return result

Ex03.exec2

from mod1 import sum, safe_sum

print(sum(10, 20))
print(safe_sum(20, 10))

if __name__ == "__main__": 의 의미

Ex03.mod1

def sum(a, b):
	return a + b

def safe_sum(a, b):
	if type(a) != type(b):
		print('더할수 있는 것이 아닙니다.')
		return
	else:
		result = sum(a, b)
	return result

print(safe_sum('a', 1))
print(safe_sum(1, 4))
print(sum(10, 10.4))

Ex03.exec3

import mod1

위와 같이 했을때 모듈로서의 기능이 없는데 왜 굳이 이렇게 할까 의문이 들 것이다.

Ex03.mod1

def sum(a, b):
	return a + b

def safe_sum(a, b):
	if type(a) != type(b):
		print('더할수 있는 것이 아닙니다.')
		return
	else:
		result = sum(a, b)
	return result

# main 함수(public static void main)
if __name__ == '__main__':
	print(safe_sum('a', 1))
	print(safe_sum(1, 4))
	print(sum(10, 10.4))

Ex03.exec3

import mod1

디버깅을 할 때 사용하는 용도로 많이 쓴다.

클래스나 변수 등을 포함한 모듈

PI = 3.141592

class Math:
	def solv(self, r):
		return PI * (r ** 2)
	
def sum(a, b):
	return a + b

if __name__ == '__main__':
	print(PI)
	a = Math()
	print(a.solv(2))
	print(sum(PI, 4.4))

위는 템플릿이다. - Module:Main을 클릭해보자

위와 같이 메인이 자동적으로 생성되서 제공된다.

새 파일 안에서 이전에 만든 모듈 불러오기

import sys print(sys.path) sys.path.append("C:/Python/module") print(sys.path)

['C:\\Python\\eclipse-workspace\\Ex03', 'C:\\Python\\eclipse-workspace\\Ex03', 'C:\\Python\\Python36\\DLLs', 'C:\\Python\\Python36\\lib', 'C:\\Python\\Python36', 'C:\\Python\\Python36\\lib\\site-packages', 'C:\\Python\\Python36\\python36.zip'] 
['C:\\Python\\eclipse-workspace\\Ex03', 'C:\\Python\\eclipse-workspace\\Ex03', 'C:\\Python\\Python36\\DLLs', 'C:\\Python\\Python36\\lib', 'C:\\Python\\Python36', 'C:\\Python\\Python36\\lib\\site-packages', 'C:\\Python\\Python36\\python36.zip', 'C:/Python/module']

import sys

print(sys.path)
sys.path.append("C:/Python/module")
print(sys.path)

import mod2

print(mod2.sum(3, 4))

동적 로딩으로 인해 module 디렉토리의 mod2를 불러와서 해당 구문을 실행할 수 있다.

위와 같은 방법은 이클립스를 사용하지 않을 때 사용한다.

반응형

댓글