본문 바로가기
  • 실행력이 모든걸 결정한다
Python

[Python 간단정리 3] 클래스 / 모듈 / 패키지

by 김코더 김주역 2023. 1. 6.
반응형

1. 클래스

1) 클래스란?

- 클래스는 객체를 만들어내기 위한 틀으로, 객체지향 프로그래밍의 핵심이 된다.

- 클래스에 의해 생성된 객체를 인스턴스라고 부른다. 따라서, 인스턴스로 객체를 관계 위주로 설명할 수 있다.

 

 

2) 클래스의 주요 키워드

(1) self

- 해당 클래스를 사용하는 인스턴스 그 자체를 뜻한다.

- 메소드의 첫 번째 인자로 항상 인스턴스가 전달된다. 인스턴스.메소드() 형태로 호출하는 경우에는 인스턴스가 자동으로 전달되고, 클래스.메소드() 형태로 호출하는 경우에는 첫 번째 인자에 인스턴스를 직접 추가해야 한다.

class Foo:
    def func1(): pass
    def func2(self):pass

f=Foo()
# f.func1() -> 오류 발생
f.func2()
Foo.func1()
# Foo.func2() -> 오류 발생
Foo.func2(f)

인스턴스를 통해 메소드를 호출하는 것과 클래스를 통해 메소드를 호출하는 것은 동작상으로는 차이가 없다.

 

(2) __init__

- 인스턴스를 만들 때 항상 실행되는 함수의 이름이다.

- __init__ 함수가 정상적으로 실행되어야 인스턴스를 생성할 수 있다.

class User:
    def __init__(self, id, password):
        self.id=id
        self.password=password
    
# user = User() -> 인자가 부족해서 오류 발생
user = User("jooyeok", "0703")

 

 

3) 클래스의 기본 구조

- class 키워드를 통해 클래스를 생성할 수 있으며, 클래스 안에는 여러 개의 변수와 함수들이 포함되어 있다. 예시를 통해 기본적인 구조를 파악해보자.

class Calculator: # 클래스의 이름 : Calculator
    a=1
    b=2
    def __init__(self):
        self.result=0
        
    def add(self, num):
        self.result+=num
    
    def get_result(self):
        return self.result
 
cal1=Calculator()
cal2=Calculator()
print(type(cal1)) # <class '__main__.Calculator'> (어떤 클래스의 인스턴스인지를 조회)

cal1.add(3)
cal1.add(5)
print(cal1.get_result()) # 8
cal2.add(4)
cal2.add(6)
print(cal2.get_result()) # 10
print(cal1.a+cal2.b) # 3

 

 

4) 클래스의 상속

- 클래스의 상속이란 다른(상위) 클래스의 변수와 메소드를 그대로 물려받고, 필요에 따라 이들을 재정의 할 수 있도록 하는 것이다.

- 클래스명 뒤 괄호 안에 상위 클래스명을 넣어주면 상위 클래스의 상속이 이루어진다.

- 아래 예시를 통해 상속에 대해 자세히 이해해보자.

class A:
    x=1
    y=2
    def __init__(self):
        print("Class A")
        
    def method1(self):
        print("Python")
        
    def method2(self):
        print("Java")


class B(A):
    y=3
    def __init__(self):
        print("Class B")
        
    def method2(self):
        print("Javascript")


b=B()
print(b.x)
print(b.y)
b.method1()
b.method2()

출력 결과는 아래와 같다.

위의 예제에서 확인할 수 있는 사실은 다음과 같다.

  • 클래스 B의 __init__() 함수는 호출되었지만, 상속받은 클래스A의 __init__() 메소드는 호출되지 않았다.
  • 클래스 B에서 클래스 A의 x값을 그대로 물려받았다.
  • 클래스 B에서 클래스 A의 y값을 재정의했으며, 재정의한 값이 사용되었다.
  • 클래스 B에서 클래스 A의 method1() 메소드를 그대로 물려받았다.
  • 클래스 B에서 클래스 A의 method2() 메소드를 재정의했으며, 재정의한 메소드가 사용되었다.

 

 

5) 연산자 오버로딩

- 객체끼리 연산자를 사용할 수 있게 하는 기법을 연산자 오버로딩이라고 한다.

- 아래 예시에서는 + 연산자를 객체에 사용할 수 있게 해주는 __add__() 함수와 - 연산자를 객체에 사용할 수 있게 해주는 __sub__() 함수를 사용한다.

class A:
    a=3

class B:
    a=5
    def func(self, other):
        print(self.a+other.a)
    def __add__(self, other):
        print(self.a+other.a) # + 연산자를 객체에 사용할 수 있게 하는 함수
    def __sub__(self, other):
        print(self.a-other.a) # - 연산자를 객체에 사용할 수 있게 하는 함수


a=A()
b=B()
b.func(a) # 8이 출력된다.
b+a # 8이 출력된다. 참고로, a+b는 오류가 발생한다.
b-a # 2이 출력된다. 마찬가지로, a+b는 오류가 발생한다.

참고로, 다른 객체가 올 매개변수의 이름은 꼭 other이 아니어도 된다.

 

 

 

2. 모듈

- 모듈이란 다른 파이썬 프로그램을 불러와 사용할 수 있게 만들어진 파이썬 파일이다.

- 다른 사람들이 이미 만들어 놓은 모듈을 사용할 수도 있고 우리가 직접 만들어서 사용할 수도 있다.

 

1) 모듈의 기본적인 사용법

- import는 이미 만들어진 파이썬 모듈을 사용할 수 있게 해주는 명령어다. 다른 모듈의 변수, 함수, 메소드를 모두 사용할 수 있게 된다.

import 모듈이름

예시

# main.py
import module1

print(module1.PI) # 3.141592
print(module1.func(3,5)) # 8
print(module1.Hello()) # <module1.Hello object at 0x000001EEA6305D10>

 

# module1.py
PI = 3.141592

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

class Hello:
    pass

 

- 메소드를 사용할 때 모듈이름을 생략하고 싶다면 다음과 같이 from 키워드를 이용하면 된다.

from 모듈이름 import 모듈함수1, 모듈함수2, ...

또는

from 모듈이름 import * # 모듈의 모든 함수를 불러옴

 

# main.py
from module1 import func

print(func(3,5)) # 8

 

이 때 현재 파일에 동일한 이름의 함수가 있다면 현재 파일에 있는 함수가 사용된다.

# main.py
from module1 import func

def func(a, b):
    return a*b

print(func(3,5)) # 15

 

 

2) if __name__=="__main__"

- 현재 파일이 직접 실행시킨 파일인지 여부를 검사하는 if문이다.

예를 들어, module1.py에 print("I am module1")을 추가했다고 해보자.

# module1.py
def func(a, b):
    return a+b

print("I am module1")

그리고 main.py를 직접 실행하면 import 시점에 module1.py에 있는 print("I am module1")가 실행된다.

# main.py
from module1 import func

print(func(3,5)) # 8

이제 module1.py에 if __name__=="__main__"을 추가해보자.

# module1.py
def func(a, b):
    return a+b

if __name__=="__main__":
    print("I am module1")

이렇게 되면 main.py를 직접 실행했을 때 print("I am module1")가 실행되지 않는다.

 

 

3) 모듈을 불러오는 또 다른 방법

(1) sys.path.append()

- sys.path은 파이썬 라이브러리들이 설치되어 있는 디렉토리들을 모아둔 리스트다. 즉, 새 디렉토리를 직접 이 리스트에 넣으면 된다.

import sys
sys.path.append(r'C:\Users\master\Desktop\python') # r prefix : \를 순수하게 문자로 사용함
# sys.path.append('C:/Users/master/Desktop/python')도 가능

 

(2) PYTHONPATH 환경 변수 사용

- set 도스 명령어를 통해 PYTHONPATH 환경 변수에 새 디렉토리를 설정하면 된다.

C:\Users\home>set PYTHONPATH=C:\Users\master\Desktop\python

 

(1), (2)와 같이 설정하면 절대 경로 설정도 같이 이루어진다.

 

 

 

3. 패키지

- 패키지는 .(점)을 활용하여 파이썬 모듈을 계층적으로 관리할 수 있다.

 

1) 패키지 만들기

- 패키지는 다음과 같이 계층적으로 구성될 수 있다.

__init__.py를 제외한 각 파일에는 다음과 같은 규칙적인 내용의 함수를 작성해두었다.

# dir1/file1.py
def info():
    print("dir1/file1.py")

 

 

2) 패키지 안의 함수 실행하기

- 다음과 같이 from, import 키워드를 이용하여 모듈을 불러오면 된다. 코드에서 사용할 수 있는건 import 부분이다.

from 모듈이름 import 나머지 모듈이름 (또는 모듈함수)

- 예를 들어 main.py에서 dir2/file1.py의 info()을 호출해보자.

# main.py
from dir2.file1 import info
info() # 'dir2/file1.py' 출력

또는

# main.py
from dir2 import file1
file1.info() # 'dir2/file1.py' 출력

 

 

3) __init__.py

- 해당 디렉토리가 패키지의 일부임을 알려주는 역할을 한다. 디렉토리에 __init__.py 파일이 없다면 패키지로 인식되지 않는다.

 

 

4) __all__

- 다음과 같이 from에 전체 모듈이름(경로)를 작성하지 않더라도 import에 *를 작성하면 나머지 모듈이름을 사용할 수 있을까? 그렇지 않다. 오류가 발생한다.

from dir2 import *
file1.info() # 오류 발생

 

- __all__은 특정 디렉토리의 모듈을 *을 이용하여 import할 때 사용된다. 해당 디렉토리의 __init__.py 파일에 __all__이라는 변수를 설정하고 import할 수 있는 모듈을 정의해 주어야 한다.

# dir2/__init__.py
__all__=['file1', 'file2']

 

from dir2 import *
file1.info() # 'dir2/file1.py' 출력

 

 

5) 부모 디렉토리 참조

- ..은 부모 디렉토리를 의미한다.

- 예를들어, dir2/file1.py에서 dir3/file2.py를 import 하고 싶다면 다음과 같이 작성하면 된다.

from ..dir3.file2 import info

 

 

● 참고 자료 : Do it! 점프 투 파이썬

 

 

반응형

댓글