Ayden's journal

class와 module

Class

파이썬의 클래스는 그 용어가 JS의 클래스와는 조금 다르다. 인스턴스는 동일하지만, 스태틱 메서드를 클래스 메서드라고 부르며, 클래스와 관련은 있지만 내부 변수와는 소통하지 않는 메서드를 스태틱 메서드라고 부른다. JS랑 파이썬이랑 왔다갔다 하면 조금 햇갈리기는 하지만, 신경 쓰면 또 그렇게까지 햇갈릴만한 건 아니다 싶다.

class User:
  count = 0 # 클래스 변수 (JS에서는 스태틱 프로퍼티)
  
  @classmethod # 데코레이터는 JS나 Python이나 비슷한듯
  def print_number_of_users(cls): # 클래스 메서드 (JS에서는 스태틱 메서드)
    return cls.count
    
  @staticmethod # self나 cls를 쓰지 않는 메서드
  def valid_email(email): # Python에서는 이걸 스태틱 메서드라 부른다
    return "@" in email
  
  def __init__(self, name, email, password): # JS의 컨스트럭터
    self.name = name
    self.email = email
    self.pasword = password
    
    User.count += 1 (재귀적 스태틱 프로퍼티 호출)
    
  def __str__(self):
    return 

  def say_hello(self):
    print(f"안녕하세요. 저는 {self.name}입니다.")
  
  def login(self, email, password)
    if ... :
      self.say_hello()

JS는 constructor 를 쓰지만, 파이썬에서는 던더 init을 사용하여 인스턴스를 초기화한다. 듣기로는 파이썬은 완전 객체 지향 언어라서 모든 것이 객체로 되어있고, 1 + 1과 같은 것도 int 클래스의 던더 메서드(혹은 매직 메서드) __add__ 호출로 처리된다. 하지만 일반적으로는 __init__과 __str__ 정도만 사용되는 듯하다.

(1).__add__(2)  # 3

 

TS에서는 키워드로 처리하지만, 파이썬에서는 데코레이터를 사용해 게터와 세터 등을 처리한다.

@classmethod # 메서드를 클래스 메서드(JS의 스태틱과 같음)로 취급
@staticmethod # 메서드를 스태틱 메서드(JS의 스태틱과 다름)로 취급
@property # 메서드를 게터로 취급
@x.setter # 메서드 x를 세터로 취급

 

상속

상속(inheritance)을 통해 기존 클래스의 기능을 확장하거나 재사용할 수 있다. 상속은 코드의 중복을 줄이고 유지보수성을 높이는 데 중요한 역할을 한다. 또한, 상속을 활용하면 계층 구조를 만들어 객체 간의 관계를 명확히 할 수 있다. super() 메서드를 사용하면 부모 클래스의 메서드를 호출하여 자식 클래스에서 중복된 코드를 최소화할 수 있다.

class Admin(User):
  def __init__(self, name, email, password):
    super().__init__(name, email, password)
    self.level = -1
    
admin = Admin("ayden", "wpfekdml@me.com", "password1234")
print(isinstance(admin, User)) # True

 

JS와 달리 파이썬은 다중 상속도 지원한다. 다만, 다중 상속의 경우 상속받는 클래스 간의 관계가 복잡해질 수 있어 신중하게 설계해야 한다. 파이썬은 이 문제를 해결하기 위해 메서드 결정 순서(Method Resolution Order, MRO)라는 규칙을 따르는데, MRO는 어떤 클래스의 메서드를 먼저 호출해야 하는지 결정하는 알고리즘으로, 일반적으로 깊이 우선 탐색(DFS)을 기반으로 동작하며, super()를 사용해 이를 간단하게 처리할 수 있다.

# 다중 상속을 받는 계산대-배달원 클래스
class CashierDeliveryMan(DeliveryMan, Cashier):
    def __init__(self, name, wage, on_standby, number_sold=0):
        Employee.__init__(self, name, wage)
        self.on_standby = on_standby
        self.number_sold = number_sold
        
print(CashierDeliveryMan.mro())
[<class '__main__.CashierDeliveryMan'>, <class '__main__.DeliveryMan'>, <class '__main__.Cashier'>, <class '__main__.Employee'>, <type 'object'>]

 

인터페이스

파이썬에는 JS와 달리 "인터페이스"라는 명시적인 키워드는 없다. 하지만 데코레이터를 사용하여 이를 유사하게 구현할 수 있다. abc 모듈을 활용하면 메서드의 껍데기만 정의하고 구체적인 구현은 서브클래스에 위임할 수 있다. 이러한 접근은 코드의 일관성을 유지하고 명시적으로 설계를 표현하는 데 유용하다.

form abc import ABC, abstractmethod

class Shape(ABC): # 추상 클래스
    @abstractmethod # 추상 메서드
    def draw(self):
      pass

 

help

help() 함수는 코드의 문서화된 내용을 쉽게 조회할 수 있도록 돕는 도구이다. 이 함수는 클래스, 함수, 모듈, 또는 객체의 설명서를 출력하여 사용자가 해당 객체의 목적과 사용법을 빠르게 이해할 수 있도록 지원한다. 예를 들어, help(str)을 호출하면 문자열 클래스와 관련된 모든 메서드와 그 설명을 확인할 수 있다.

설명서를 작성하는 스타일에는 크게 두 가지가 있는데, 구글의 방식과 파이썬 공식 방식이 그것이다. 당연하지만 언제나 팀의 컨벤션이 우선이다.

help(User)

# Google Docstring:
"""유저에서 추천할 영상을 찾아준다
Parameters:
number_of_suggestions (int): 추천하고 싶은 영상 수. 기본값은 5

Returns:
list: 추천할 영상 주소가 담긴 리스트
"""

# reStructuredText (파이썬 공식 문서화 기준):
"""유저에서 추천할 영상을 찾아준다
:param number_of_suggestions: 추천하고 싶은 영상 수. 기본값은 5
:type number_of_suggestions: int

:returns: 추천할 영상 주소가 담긴 리스트
:rtype: list
"""

 

 

모듈

파이썬 모듈은 ESM과 다르게 동작하는 듯하다. 기본적으로는 하나의 .py 파일을 의미하며, 관련된 코드, 함수, 클래스, 변수 등을 하나의 파일에 묶어서 정의한 것으로, 이를 통해 다른 파이썬 스크립트에서 재사용할 수 있다. 하지만 ESM의 import 행위가 파일을 '실행'하는 것은 아니지만, 파이썬에서는 실행하는 행위거나 그와 유사한 듯하다.

때문에 모듈에서 실행해야 하는 부분은 main에 넣어두고, 조건문을 사용해 해당 모듈이 스크립트로서 실행되는지 여부를 확인해 처리한다. __name__은 모듈의 이름을 저장해 놓은 변수인데, .py 파일을 직접 실행하면 __name__은 __main__이 되지만, import하면 모듈 이름이 된다.

import area

# 면적 계산기 프로그램
def main():
    x = float(input('원의 지름을 입력해 주세요: '))
    print('지름이 {}인 원의 면적은 {}입니다.\n'.format(x, area.circle(x)))

    y = float(input('정사각형의 변의 길이를 입력해 주세요: '))
    print('변의 길이가 {}인 정사각형의 면적은 {}입니다.'.format(y, area.square(y)))

if __name__ == '__main__':
    main()

 

자바스크립트에서 모듈 가져오기는 import만 하는 행위지만, 파이썬에서는 모듈 가져오기는 import이면서 동시에 export이기도 한 듯하다. 이는 기본적으로 '무엇을 내보낼지' 조건적으로 처리할 수 없기 때문이 아닐까 한다. 따라서 네임스페이스 중복 문제를 해결하기 위해 가능하면 모듈 전체를 불러와서 내부 함수를 메서드처럼 쓰는 것이 좋을 듯하다.

# 모듈 전체 불러오기
import calc

calc.add(1, 2)

# 모듈의 특정 메서드만 불러오기
from calc import add, subtract

add(1, 2)
subtract(5, 3)

dir() # 네임스페이스 리턴

 

다양한 내장 모듈

파이썬은 다양한 내장 모듈을 지원하고 추가적으로 필요한 모듈이 있다면 pip를 사용해 프로젝트에 설치할 수 있다.

import math

# 코사인 함수 (모든 삼각함수는 라디안을 사용합니다)
print(math.cos(0)) # 1.0

# 로그 함수
print(math.log10(100)) # 2.0
import random

# 랜덤한 정수 1 <= N <= 20 
print(random.randint(1, 20)) # 3

# 랜덤한 소수 0 <= x <= 1
print(random.uniform(0, 1)) # 0.599056286966887
import datetime 

# 현재 시간과 날짜
today = datetime.datetime.now()
print(today)

# 출력값을 "요일, 월 일 연도"로 포매팅
print(today.strftime("%A, %B %dth %Y"))

# 특정 시간과 날짜
pi_day = datetime.datetime(2020, 3, 14, 13, 6, 15)
print(pi_day)

# 두 datetime의 차이
print(today - pi_day)
import os

# 현재 어떤 계정으로 로그인 돼있는지 확인
print(os.getlogin())

# 현재 파일의 디렉토리 확인 
print(os.getcwd())

# 현재 프로세스 ID 확인 
print(os.getpid())
import os.path

# 프로젝트 디렉토리 경로 '/Users/codeit/PycharmProjects/standard_modules'
# 현재 파일 경로 '/Users/codeit/PycharmProjects/standard_modules/main.py'

# 주어진 경로를 절대 경로로
print(os.path.abspath('..'))

# 주어진 경로를 현재 디렉토리를 기준으로 한 상대 경로로
print(os.path.relpath('/Users/codeit/PycharmProjects'))

# 주어진 경로들을 병합
print(os.path.join('/Users/codeit/PycharmProjects', 'standard_modules'))
import re 

# 알파벳으로 구성된 단어들만 매칭
pattern = re.compile('^[A-Za-z]+$')
print(pattern.match('I'))
print(pattern.match('love'))
print(pattern.match('python3'))

print()

# 숫자가 포함된 단어들만 매칭
pattern = re.compile('.*\d+')
print(pattern.match('I'))
print(pattern.match('love'))
print(pattern.match('python3'))
import json

# 딕셔너리 오브젝트
obj = {'my': 'dictionary'}  

# obj를 filename.json 파일에 저장
with open('filename.json', 'w') as f:
    json.dump(obj, f)

# filename.json에 있는 오브젝트를 읽어옴 
with open('filename.json', 'r') as f:
    obj = json.load(f)

print(obj) # {'my': 'dictionary'}

블로그의 정보

Ayden's journal

Beard Weard Ayden

활동하기