본문 바로가기

1. Python

3/10(금) IT K-DT (7일차) / 16.객체지향과클래스~19.모듈

 

 

16. 객체지향과 클래스

 

16-4. 메소드(Method)

 

16-4-1. 메소드 정의하기

메소드(Method) : 해당 'Class의 객체에서만' 호출이 가능한 함수. (= Class의 함수)
해당 개체의 속성에 대한 연산을 행하며, 객체이름.메소드명() 의 형태로 호출을 함.

 

메소드 생성의 예시


class Counter:
  def __init__(self): 
    self.num = 0 # 초기화 되어있고, 항상 0만 출력되고있는 상태

  def increment(self):
    self.num += 1 # 버튼을 누를 때마다 1씩 증가

  def decrement(self):
    self.num -= 1 # 버튼을 누를 때마다 1씩 감소

  def current_value(self):
    return self.num # 현재의 값을 확인

  def reset(self):
    self.num = 0 # 현재의 값을 리셋



메소드 활용의 예시



KBbank = Counter()
print(KBbank.num)
0

KBbank.increment()
print(KBbank.num)
1

KBbank.decrement()
print(KBbank.num)
0

print(KBbank.current_value())
0

KBbank.increment()
KBbank.increment()
KBbank.increment()
KBbank.increment()
KBbank.increment()
print(f'{KBbank.current_value()}') # KBbank의 숫자를 5씩 늘림
5

Hanabank = Counter()
print(f'{Hanabank.current_value()}')
0

Hanabank.increment()
Hanabank.increment()
Hanabank.increment()
print(f'{Hanabank.current_value()}') #Hanabank의 숫자를 3씩 늘림
3

Hanabank.reset()
print(f'{Hanabank.current_value()}') # Hanabank의 숫자를 리셋

 


은닉성(Encapsulation) :
파이썬은 객체 지향 프로그래밍을 지원하며, 이에 따라 클래스와 객체를 사용할 수 있음.
은닉성은 객체 지향 프로그래밍의 특징 중 하나로, 클래스 내부의 상태 정보를 보호하고 외부에서 직접 접근하지 못하게 하는 것을 의미.

파이썬에서는 속성(Attributes)과 메서드(Methods)를 사용하여 객체의 상태와 동작을 정의함.

속성은 객체의 데이터를 저장하며, 메서드는 객체의 동작을 정의함.
이때 속성과 메서드를 적절하게 캡슐화하여 외부에서 직접적인 접근을 제한하면 은닉성을 구현할 수 있음.

파이썬에서는 은닉성을 구현하기 위해 이름 맹글링(Name Mangling)이라는 기능을 제공함.

이름 맹글링은 속성이나 메서드 이름 앞에 언더바 두 개(__)를 붙여서 외부에서 직접 접근할 수 없게 만드는 것임.
그러나 속성이나 메서드 이름을 직접 바꾸면 접근이 가능하기 때문에 완벽한 은닉성을 보장하지는 않음.

따라서 파이썬에서는 보안을 강화하기 위해 은닉성을 구현하는 대신에 속성이나 메서드에 대한 접근 제한을 설정하는 방법을 권장함.

이를 위해서는 속성이나 메서드 이름 앞에 언더바 한 개(_)를 붙여서 내부적으로 사용되는 것임을 나타내고,
외부에서 접근하지 말아야 하는 것임을 알려줄 수 있음.

 

16-4-2. 메소드의 유형

1) 인스턴스 메소드(instance method) : 해당 메소드를 호출한 객체에서만 사용.
2) 클래스 메소드(class method) : 클래스 이름으로 호출하는 메소드. 객체를 생성하지 않음. 

(메소드 선언 위에 @staticmethod라고 표기)

class Math: # property 2개(add, multiply) 생성
  def add(self, x, y):
    return x+y
  def multiply(self, x, y):
    return x*y  

math = Math() # 객체 생성

result1 = math.add(10,3)
print(result1) # add라는 method 사용

result2 = math.multiply(10,3)
print(result2) # multiply라는 method 사용


13
30

class Math:

  @staticmethod # class method는 메소드 선언 위에 @staticmethod라고 표기
  def add(x, y):
    return x+y

  @staticmethod # class method는 메소드 선언 위에 @staticmethod라고 표기
  def multiply(x, y):
    return x*y 
# @staticmethod는 'self'를 사용하지 않음

  def div(x, y):
    return x / y 
# 하나의 class에 인스턴스, 클래스를 모두 사용할 수 있음.

result1 = Math.add(10,3)
print(result1)

result2 = Math.multiply(10,3)
print(result2)


13
30

result3 = Math.div(10, 3)
print(result3) 
# staticmethod를 표기하지 않아 self가 없어서 오류가 나야하지만, 프로그램이 자동으로 수정.


3.3333333333333335

math = Math()
result3 = Math.div(10, 3)
print(result3)


3.3333333333333335

 


정적 메서드(static method)
static method는 클래스에 속하지만, 인스턴스에는 속하지 않는 메서드. 

클래스의 상태나 인스턴스의 상태와 관계가 없는 일반적인 기능을 구현하는데 사용됨. 
이러한 메서드는 인스턴스가 생성되지 않아도 호출될 수 있음.

static method는 @staticmethod 데코레이터를 사용하여 정의됨. 

@staticmethod 데코레이터는 해당 메서드가 static method임을 표시함. 
static method는 인스턴스 메서드와 달리 첫 번째 매개변수로 self를 사용하지 않음.
self가 인스턴스 자체를 참조하는데 static method는 클래스 인스턴스에 접근할 수 없기 때문.


 

17. 상속

 

17-1. 상속

기존에 정의해둔 class의 기능을 물려받는 것.
클래스 간에 코드를 공유하여 재사용성을 높임.
기존 class에 기능 일부를 추가하거나, 변경하여 새로운 class를 정의함.
    기존 class : 부모/parent/super/base class
    새로운 class : 자식/child/sub class
새로운 class에서는 필요한 기능을 추가하거나 재정의할 수도 있음.
코드의 중복을 줄이고, 유지 보수성과 확장성을 높일 수 있음.

class Animal:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  def eat(self, food): # eat이라는 새로운 method 생성
    print(f'{self.name}은/는 {food}를 먹습니다.')
  def sleep(self, hour): # sleep이라는 새로운 method 생성
    print(f'{self.name}은/는 {hour}시간 동안 잠을 잡니다.')

 
animal = Animal('동물', 10)
animal.eat('먹이')
animal.sleep(14)
동물은/는 먹이를 먹습니다.
동물은/는 14시간 동안 잠을 잡니다.

class Dog(Animal): # Dog class에서 상속받고자하는 class인 Animal class를 소괄호 안에 넣음.
  pass
# Rucy = Dog() 
# Animal class를 상속받았지만, 매개변수가 없어서 Rucy = Dog()을 그대로 실행시키면 에러가 발생. 
# TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'
Rucy = Dog('루시', 12) # 매개변수를 입력해준 후 method를 생성하면 정상적으로 작동함.
Rucy.eat('사료')
Rucy.sleep(10)


루시은/는 사료를 먹습니다.
루시은/는 10시간 동안 잠을 잡니다.


17-2. 메소드 오버라이딩

부모 class의 method를 재정의하여 자식 class의 instance로 호출 시 재정의된 method가 호출됨.
부모 class에서 정의한 기능을 수정하거나, 새로운 기능을 추가할 수 있음.

 

class Animal:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  def eat(self, food): 
    print(f'{self.name}은/는 {food}를 먹습니다.')
  def sleep(self, hour):
    print(f'{self.name}은/는 {hour}시간 동안 잠을 잡니다.')    

class Dog(Animal):
  def run(self):
    print(f'{self.name}은/는 달립니다')
  def eat(self, food): # 위의 부모 class의 eat method를 재정의할 예정. 메소드 오버라이딩.
    print(f'{self.name}은/는 {food}를 아주 맛있게 먹습니다.')
  def superEat(self, food):
    super().eat(food)
 #super() : 부모 class를 불러주는 method. 자식 class는 부모 class의 method의 오버라이딩도 가능하다.

Rucy = Dog('루시', 12)
Rucy.eat('사료')
Rucy.run()


루시은/는 사료를 아주 맛있게 먹습니다.
루시은/는 달립니다


17-3. 다중 상속

둘 이상의 부모 Class로부터 상속을 받는 것. 상속을 하는 부모 Class의 수는 제한이 없음.
C#, Java 언어는 다중상속이 불가능하지만 C++,Python 언어는 다중상속이 가능하다.
코드를 복잡하게 만들 수 있고, 상속받은 메서드 이름이 충돌할 가능성도 있어 다수의 상속은 비추천함.
(상속하거나 상속받는 class의 property안의 소괄호가 각각 다르면 Error가 발생함)

 

class Animal:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  def eat(self, food): 
    print(f'{self.name}은/는 {food}를 먹습니다.')
  def sleep(self, hour):
    print(f'{self.name}은/는 {hour}시간 동안 잠을 잡니다.')    

class Human:
  def __init__(self, name, age):
    self.name = name
    self.age = age
  def study(self, hour): 
    print(f'{self.name}은/는 {hour}시간 동안 공부를 합니다.')

class KimApple(Animal, Human): # Animal과 Human의 Class를 둘 다 상속받겠다는 의미.
  pass
kim = KimApple('김사과', 20) # kim이라는 객체는, KimApple()의 Class를 참조하여 method를 가져옴.
kim.eat('밥')
kim.study(2)


김사과은/는 밥를 먹습니다.
김사과은/는 2시간 동안 공부를 합니다.

 

mro() : KimApple이라는 Class가 현재 갖고있는 object를 보여줌 (상속 현황 포함)
KimApple.mro() 
[__main__.KimApple, __main__.Animal, __main__.Human, object]

 

18. 스페셜 메소드(Special method)

 

18-1. 스페셜 메소드(Special method)

언더바 2개()로 시작해서 언더바 2개()로 끝나는 특수함수. (예: _ _init_ _)
class의 instance를 생성하거나 class 간의 연산을 수행할 때 자동으로 호출.
해당 method들을 재구현하면 객체에 여러가지 내장 함수나 연산자에 원하는 기능을 부여할 수 있음. 

이러한 기능이 있어 python에서 객체 지향 프로그래밍을 구현할 때 매우 유용함.
아무 함수만 가능한 것은 아니고, 메소드가 제공이 되는 함수에 한정해서만 가능

 

class Point:
  def __init__(self, x, y): # 사실, 생성자도 special method의 일종임.
    self.x = x
    self.y = y
  def print_point(self):    # (3,4)로 출력을 해줄 예정.
    print(f'{self.x}, {self.y}')
    
p1 = Point(3,4)
p1.print_point()


3, 4

 

18-1-1.  __str__()의 사용

 

class Point:
  def __init__(self, x, y): # 사실, 생성자도 special method의 일종임.
    self.x = x
    self.y = y
  def __str__(self): # str()함수를 오버라이딩. 기존에 사용하던 기능을 덮어쓰는 상황.
    return (f'{self.x}, {self.y}') # print가 아닌 return으로 바꿔야 함.
    
print(p1) # 데이터주소 및 object가 어떤 class의 출처인지를 알 수 있음.
print(str(p1))

<__main__.Point object at 0x7f3661f111c0>
<__main__.Point object at 0x7f3661f111c0>

#사실 str()이라는 method가 포함이 되어야 하나, 자동으로 입력되어 출력되도록 생략이 되어있는 것임.

 

 

18-1-2. __add__()의 사용

# 연산을 목적으로 'p1+p2' 를 단순히 작성해서 실행하면 Error가 발생.
# TypeError: unsupported operand type(s) for +: 'Point' and 'Point'

 

class Point:
  def __init__(self, x, y):
    self.x = x
    self.y = y
  def print_point(self): 
    print(f'{self.x}, {self.y}')
  def __str__(self):
    return (f'{self.x}, {self.y}')
  def __add__(self, pt): 
  # (+) 연산자를 오버라이딩 (객체 + 객체). pt는 Point에 대한 x,y 좌표가 들어가는 객체.
    new_x = self.x + pt.x
    new_y = self.y + pt.y
    return Point (new_x, new_y)
    
p1 = Point(3,4)
p2 = Point(5,8)
 print(p1+p2)


8, 12

 

18-1-3. __len__()의 사용

 

class Point:
  def __init__(self, x, y):
    self.x = x
    self.y = y
  def __len__(self):
    return self.x+self.y # len() x+y로 오버라이딩하는 경우
    
p1 = Point(3,4) 
# 그냥 print(len(p1)) 을 실행시키면 오류가 발생. Point는 len()을 사용할 수 없는 구조이기 때문.
print(len(p1)) 
# 그러나 위의 식처럼 오버라이딩 후 실행하면 객체 p1의 len()함수가 x+y로 출력이 됨.


7

18-1-4. __getitem__()의 사용

class Point:
  def __init__(self, x, y):
    self.x = x
    self.y = y
  def __getitem__(self, index):  
  # 'index'를 꼭 남겨줘야함. getitem()이 index나 slice를 지원하는 함수이기 때문.
    if index ==0 :  # indexing의 기능을 오버라이딩하는 경우.
        return self.x
    elif index ==1 :
        return self.y
    else:
        return -1
        
p1 = Point(3,4) 
print(p1[0])
print(p1[1])
print(p1[2])
# [0]은 3, [1]은 4, 이외의 잘못된 숫자의 입력은 -1이 출력


3
4
-1

 

 


Object class

python에서 모든 class의 최상위 class.
모든 class는 기본적으로 object 클래스를 상속받음.
즉, object class는 python에서 모든 객체의 부모 class이며, 모든 객체는 object class의 instance.



 

19. 모듈(module)

 

19-1. 모듈(module)

함수, 클래스, 변수 등을 정의하고, 다른 파이썬 스크립트에서 이를 재사용할 수 있게 하는 파일.
모든 python 파일(.py)은 모듈이다.

 

 

1) 모든 모듈의 전체 함수 가져오기


import 모듈명


사용
모듈명.함수명()



start부터 end까지의 숫자의 합을 구하는 함수

def total(start, end):
    sum = 0
    for i in range(start, end+1):
        sum += i
    return sum


num1과 numc2의 사칙연산의 결과를 반환해주는 함수

def calc(num1, num2):
    return num1+num2, num1-num2, num1*num2, num1/num2


__name__ : 파이썬이 내부적으로 사용하는 특별한 변수 이름
.py 파일이 직접 실행될 경우 __name__ 변수에 __main__값이 자동으로 저장이 됨.
다른 파이썬 모듈에서 import하여 .py 파일을 사용할 경우 __name__에 모듈의 이름 값이 저장이 됨.

 

if __name__ == '__main__':
    print(total(1,100))
    print(calc(1,100))

 

VS code에서 작성한 .py파일을 저장한 후, Colab에서 .py파일을 모듈로 import해서 열 수 있음. 
일회용이라 Colab을 종료하면 불러온 파일도 사라짐.

util.total(1,100)
util.calc(10,3)

 

5050
(13, 7, 30, 3.3333333333333335)

 

 

2) 특정 함수만 골라서 가져오기


from 모듈명 import 함수1, 함수2 ...


사용

함수명()


 

from util import calc
calc(1,100) # 모듈명인 .util을 작성할 필요가 없음.

 

(101, -99, 100, 0.01)

 

# calc()에서 나누기 부분만 사용하고 싶을 때는 다른 부분은 언더바(_)를 사용하고, 
# 나누기 연산이 위치한 부분은 result를 사용한다.

 

_,_,_,result = calc(10,3)
print(result)


3.3333333333333335

 

3) 모든 모듈의 함수 가져오기


from 모듈명 import *

사용
함수명()

 

from util import *
total(1,100) # 모듈명인 .util을 작성할 필요가 없음.

 

5050


4) 모듈에 별명 붙여 불러오기


import 모듈명 as 별명 # 모듈명이 너무 길어서 작성하기가 어려울 때 사용

사용
별명.함수명()

 

import util as ut
ut.total(1,100)


5050

 


19-2. 구글 드라이브 활용

VS code에서 작성한 .py파일을 저장한 후, Colab에서 .py파일을 모듈로 import해서 열 수 있지만,

일회용이라 Colab을 종료하면 불러온 파일도 사라짐.
며칠에 걸쳐 코드를 작성해야 하는 경우 매우 불편한 상황이 초래됨.
불편한 상황을 해결하기 위해서는 Google Drive에 아예 VS code에서 작성한 .py파일을 저장해두면 됨.
이후 Google Colab의 파일 탭에서 드라이브 마운트 설정 클릭 후 활용 가능.

(하지만, 구글드라이브의 드라이브 마운트 설정 또한 일일이 진행해야 함.)

 


util = '/content/drive/MyDrive/python/day2'   # 파일 이름.py를 제외하고 그 직전의 폴더까지 경로복사

import sys 
sys.path.append(util)



19-3. 클래스를 포함한 모듈을 이용

 

# VS code를 사용해 만든 util2.py파일을 ut2라는 별명으로 불러오는 상황

 

import util2 as ut2

'''
util2.py의 내용

PI = 3.141592
class Math:
    def circle(self, r):
        return PI * (r**2)
    def add(self,a,b):
        return a+b
'''

math = ut2.Math()
math.circle(5)

math.add(10,4)

 

78.5398
14


19-4. 패키지

모듈의 상위 개념. 일반적으로 관련된 모듈을 그룹화하여 더 큰 기능 단위로 나누는 것이 목적.
모듈이 모여있는 디렉토리로, 모듈들을 구조적으로 정리하여 코드의 재사용성과 유지보수성을 높여줌.


19-4-1. 패키지 관리자

외부 모듈을 설치 또는 삭제하기 위한 프로그램
윈도우 명령 프롬프트 또는 터미널에서 사용 가능. (python -m + [명령어])
pip 명령을 사용 (python을 설치할 시 pip도 함께 설치됨)
    1) 패키지 설치 : pip install 'package_name'
    2) 패키지 업그레이드 : pip install --upgrade 'package_name'
    3) 패키지 삭제 : pip uninstall 'package_name'
    4) pip의 버전 확인 : pip --version