반응형
파이썬 변환 지정자(conversion specification) !r, !s, !a 설명

파이썬 변환 지정자(conversion specification) !에 대해

설명

  • 파이썬의 f-string(Formatted String Literal)이나 str.format()에서 변환 지정자(conversion specification) !를 사용하면, 출력할 값을 특정 방식으로 변환할 수 있습니다.
  • 주로 !r, !s, !a가 사용됩니다.
    • !r : repr()로 변환 (개발자 친화적, 디버깅용, 공식적 표현)
    • !s : str()로 변환 (사용자 친화적, 읽기 쉬운 표현)
    • !a : ascii()로 변환 (비ASCII문자 이스케이프)

예제

class Card:
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __repr__(self):
        return f"Card(rank={self.rank!r}, suit={self.suit!r})"

    def __str__(self):
        return f"{self.rank}{self.suit}"

c = Card("A", "♠")

print(f"{c!r}")  # Card(rank='A', suit='♠')   (repr)
print(f"{c!s}")  # A♠                        (str)
print(f"{c!a}")  # Card(rank='A', suit='\\u2660') (ascii)
    

상세 설명

  • !r : repr(obj)를 호출하여 객체의 공식적 문자열 표현을 출력합니다.
    디버깅, 로깅, 개발자용 출력에 적합합니다.
  • !s : str(obj)를 호출하여 객체의 사용자 친화적 문자열 표현을 출력합니다.
    일반적인 출력, 사용자 메시지 등에 적합합니다.
  • !a : ascii(obj)를 호출하여 비ASCII문자를 이스케이프 처리한 문자열을 출력합니다.
    국제화, 이스케이프가 필요한 상황에 적합합니다.

참고 자료

반응형
반응형
@dataclass 장식자 설명

@dataclass 장식자란?

  • @dataclass는 Python 3.7 이상에서 제공하는 표준 라이브러리 dataclasses 모듈의 데코레이터입니다.
  • 클래스 정의를 간결하게 하면서, 자동으로 생성자(__init__), 비교(__eq__), 출력(__repr__) 등의 메서드를 만들어줍니다.
  • 주로 데이터 저장용 객체(값 객체, DTO 등)를 만들 때 사용합니다.

기본 사용법

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1)         # Point(x=1, y=2)
print(p1 == p2)   # True
    

자동으로 만들어지는 메서드

  • __init__: 생성자
  • __repr__: 객체의 문자열 표현
  • __eq__: 동등성 비교
  • 필요에 따라 order=True 옵션으로 __lt__, __le__ 등 비교 연산자도 자동 생성

옵션 예시

from dataclasses import dataclass

@dataclass(order=True, frozen=True)
class Card:
    rank: int
    suit: str

# order=True : 크기 비교 연산자 자동 생성
# frozen=True : 불변(immutable) 객체로 만듦 (값 변경 불가)
    

요약

  • @dataclass는 데이터 중심 클래스를 쉽고 간결하게 정의할 수 있게 해줍니다.
  • 자동으로 생성자, 비교, 출력 등 메서드를 만들어주므로 코드가 짧아지고 가독성이 좋아집니다.
반응형
반응형

 

__repr__() 메서드란?

설명

  • __repr__()는 파이썬의 특별 메서드(매직 메서드) 중 하나로, 객체의 공식적 문자열 표현을 반환합니다.
  • 주로 repr(obj) 함수나, 대화형 셸에서 객체를 입력했을 때 호출됩니다.
  • 목표는 "이 문자열을 eval()에 넣으면 동일한 객체가 생성될 수 있도록" 하는 것이지만, 꼭 그럴 필요는 없습니다.
  • 디버깅, 로깅, 객체의 내부 상태를 명확히 보여주고 싶을 때 유용합니다.

예제

class Card:
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __repr__(self):
        return f"Card(rank={self.rank!r}, suit={self.suit!r})"

c = Card("A", "♠")
print(repr(c))  # Card(rank='A', suit='♠')
print(c)        # Card(rank='A', suit='♠') (만약 __str__이 없으면 __repr__이 대신 호출됨)
    

실제 예시 

class Card:
    ...
    def __repr__(self) -> str:
        return f"{self.__class__.__name__}(suit={self.suit!r}, rank={self.rank!r})"
    ...
    
  • 이 구현은 객체의 클래스명, suit, rank 정보를 명확하게 보여줍니다.
  • 예시 출력: Card(suit='♠', rank='A')

요약

  • __repr__()는 객체의 "공식적"이고, 개발자 친화적인 문자열 표현을 제공합니다.
  • 디버깅, 로깅, 대화형 셸에서 객체의 상태를 명확히 파악할 수 있게 해줍니다.

참고 자료

반응형
반응형

 

Hand3 클래스 분석

Hand3 클래스는 다양한 방식으로 객체를 생성할 수 있도록 설계된 카드 핸드(Hand) 클래스입니다.
핵심 특징과 동작 방식은 다음과 같습니다.

1. 생성자 오버로딩 지원

  • @overload 데코레이터를 사용해 타입 힌트로 여러 생성자 시그니처를 제공합니다.
    • Hand3(Hand3) : 기존 Hand3 객체로부터 복사(클론) 생성
    • Hand3(Card, Card, Card) : 세 개의 카드로 새 핸드 생성

2. 실제 생성자 구현

def __init__(
    self,
    arg1: Union[Card, "Hand3"],
    arg2: Optional[Card] = None,
    arg3: Optional[Card] = None,
) -> None:
    self.dealer_card: Card
    self.cards: List[Card]

    if isinstance(arg1, Hand3) and not arg2 and not arg3:
        # 기존 Hand3 객체로부터 복사
        self.dealer_card = arg1.dealer_card
        self.cards = arg1.cards
    elif (
        isinstance(arg1, Card) and isinstance(arg2, Card) and isinstance(arg3, Card)
    ):
        # 세 장의 카드로 새 핸드 생성
        self.dealer_card = cast(Card, arg1)
        self.cards = [arg2, arg3]
    
  • 첫 번째 인자가 Hand3이고 나머지가 없으면 복사 생성
  • 첫 번째, 두 번째, 세 번째 인자가 모두 Card이면 새 핸드 생성

3. 속성

  • self.dealer_card: 딜러의 카드 (Card 타입)
  • self.cards: 플레이어의 카드 리스트 (List[Card])

4. 문자열 표현

def __repr__(self) -> str:
    return f"{self.__class__.__name__}({self.dealer_card!r}, *{self.cards})"
    
  • 객체를 보기 좋게 출력해줌

5. 예시

# 새 핸드 생성
h = Hand3(card1, card2, card3)

# 기존 핸드 복사
memento = Hand3(h)
    

6. 요약

  • Hand3는 복사 생성카드 3장으로 생성 두 가지 방식을 지원
  • 생성자 오버로딩을 타입 힌트로 명확히 표현
  • 내부적으로 딜러 카드와 플레이어 카드 리스트를 관리
  • 복잡한 게임 로직에서 핸드의 상태를 쉽게 복제하거나 새로 만들 수 있도록 설계됨

@overload에 대한 설명

네, 맞습니다.  
아래와 같은 @overload 데코레이터와 함께 여러 개의 __init__ 시그니처를 정의하는 것은 타입 힌트(type hint)를 명확히 하기 위한 용도입니다. from typing import overload class Hand3: @overload def __init__(self, arg1: "Hand3") -> None: ... @overload def __init__(self, arg1: Card, arg2: Card, arg3: Card) -> None: ... def __init__(self, arg1, arg2=None, arg3=None): # 실제 구현 ...
  • 실제로 파이썬에서는 __init__을 여러 번 정의할 수 없고, 오직 마지막에 정의된 __init__만 사용됩니다.
  • @overload는 타입 검사기(mypy 등)에게 "이 클래스의 생성자는 이런 여러 형태로 호출될 수 있다"는 정보를 제공합니다.
  • 런타임에는 아무 영향이 없고, 코드 가독성 및 정적 타입 체크에만 도움이 됩니다.

즉, @overload는 타입 힌트와 정적 분석 도구를 위한 용도이며, 실제 동작은 마지막에 정의된 __init__에서 처리합니다.

반응형
반응형

 

@classmethod와 @staticmethod의 차이

@staticmethod

  • 클래스와 인스턴스에 관계없이 독립적으로 동작하는 메서드입니다.
  • 첫 번째 인자로 selfcls를 받지 않습니다.
  • 클래스 이름이나 인스턴스 이름으로 모두 호출할 수 있습니다.
  • 주로 클래스와 관련된 유틸리티 함수(부가 기능)를 정의할 때 사용합니다.
class MyClass:
    @staticmethod
    def add(x, y):
        return x + y

MyClass.add(1, 2)  # 3
obj = MyClass()
obj.add(1, 2)      # 3
    

@classmethod

  • 첫 번째 인자로 클래스를 나타내는 cls를 받습니다.
  • 클래스 자체에 작용하는 메서드입니다.
  • 클래스 이름이나 인스턴스 이름으로 모두 호출할 수 있습니다.
  • 주로 클래스의 상태를 변경하거나, 다양한 방식의 생성자를 만들 때 사용합니다.
class MyClass:
    count = 0

    @classmethod
    def increment(cls):
        cls.count += 1

MyClass.increment()
print(MyClass.count)  # 1

obj = MyClass()
obj.increment()
print(MyClass.count)  # 2
    

요약

  • @staticmethod: self, cls 없이 독립적으로 동작하는 함수
  • @classmethod: 첫 인자로 cls를 받아 클래스 자체에 작용하는 함수
  • 둘 다 클래스와 인스턴스에서 호출할 수 있지만, 동작 방식과 용도가 다릅니다.
반응형
반응형
def func(a, b, *c, d, e):
	print(a,b,c,d,e)
    
func(1, 2, 3, 4, d=5, e=6)

 

파이썬 * 파라미터(가변 인자) 사용법

1. *args의 의미와 사용법

  • 함수 정의에서 *args임의 개수의 위치 인자를 튜플로 받습니다.
  • 함수 호출 시 여러 개의 값을 한 번에 받을 때 사용합니다.
def print_numbers(*args):
    for n in args:
        print(n)

print_numbers(1, 2, 3)  # 1, 2, 3 출력
    

2. **kwargs의 의미와 사용법

  • 함수 정의에서 **kwargs임의 개수의 키워드 인자를 딕셔너리로 받습니다.
  • 함수 호출 시 이름이 지정된 인자들을 한 번에 받을 때 사용합니다.
def print_key_values(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_key_values(a=1, b=2)  # a: 1, b: 2 출력
    

3. *의 다양한 사용 예시

  • 함수 호출 시 리스트/튜플을 여러 인자로 분해할 때 사용합니다.
  • 함수 정의에서 *만 단독으로 쓰면, 그 뒤의 인자는 반드시 키워드로만 전달해야 합니다.
def foo(a, b, c):
    print(a, b, c)

lst = [1, 2, 3]
foo(*lst)  # 1 2 3

def bar(a, *, b, c):
    print(a, b, c)

bar(1, b=2, c=3)  # b, c는 반드시 키워드로만 전달
    

4. *args**kwargs를 함께 사용하는 예시

def example(a, *args, **kwargs):
    print("a:", a)
    print("args:", args)
    print("kwargs:", kwargs)

example(1, 2, 3, x=10, y=20)
# a: 1
# args: (2, 3)
# kwargs: {'x': 10, 'y': 20}
    

5. 클래스 생성자에서의 * 사용 예시

class Hand2:
    def __init__(self, dealer_card, *cards):
        self.dealer_card = dealer_card
        self.cards = list(cards)

h = Hand2('J♣', '2♠', 'A♦')
print(h.dealer_card)  # J♣
print(h.cards)        # ['2♠', 'A♦']
    

6. 가변 인자 사용 시 

def func(a, b, *c, d, e):
	print(a,b,c,d,e)
    
func(1, 2, 3, 4, d=5, e=10)

7.요약

  • *args: 임의 개수의 위치 인자(튜플)
  • **kwargs: 임의 개수의 키워드 인자(딕셔너리)
  • 함수 호출 시 *리스트, **딕셔너리로 인자 분해 가능
  • 함수 정의에서 * 뒤 인자는 키워드 전용 인자
반응형
반응형

 

🚀 Python 프로젝트에서 TOML과 uv 사용법

Python 프로젝트에서 TOML 파일은 설정 관리를 위한 표준으로 자리 잡았으며, 최신 패키지 관리 도구인 uv와 함께 사용될 때 개발 효율성을 크게 높여줍니다. 이 가이드에서는 두 가지 주요 연동 방식을 설명합니다.


⚙️ 1. uv와 pyproject.toml 연동: 프로젝트 관리

uvpipvenv를 대체하는 차세대 도구입니다. uvpyproject.toml 파일을 프로젝트의 공식 설명서로 사용하여, 프로젝트의 의존성을 설치하고 개발 환경을 구성합니다.

일반적인 사용 흐름

1) pyproject.toml 파일 작성

프로젝트의 기본 정보와 실행에 필요한 라이브러리(의존성)를 정의합니다.

# pyproject.toml

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "my-fast-api-app"
version = "0.1.0"
dependencies = [
    "fastapi",
    "uvicorn[standard]",
    "requests",
]

[project.dependencies] 섹션에 명시된 패키지들을 uv가 자동으로 설치합니다.

2) uv로 가상 환경 생성 및 의존성 설치

터미널에서 아래 명령어들을 실행하여 개발 환경을 설정합니다.

# 1. 'uv'로 가상 환경(.venv) 생성
$ uv venv

# 2. 가상 환경 활성화
# (macOS/Linux)
$ source .venv/bin/activate
# (Windows)
$ .\.venv\Scripts\activate

# 3. pyproject.toml을 기준으로 의존성 설치
$ uv pip install .

🐍 2. Python 코드와 config.toml 연동: 애플리케이션 설정

API 키, 데이터베이스 정보 등 민감하거나 자주 바뀌는 설정값들은 별도의 config.toml 파일로 분리하여 관리하는 것이 좋습니다. Python 코드는 이 파일을 직접 읽어 설정값을 사용합니다.

일반적인 사용 흐름

1) config.toml 파일 작성

애플리케이션에 필요한 설정들을 TOML 형식으로 저장합니다.

# config.toml

[database]
url = "sqlite:///./test.db"
username = "admin"

[api_keys]
google_api_key = "YOUR_SECRET_API_KEY_HERE"

2) Python 코드에서 설정 파일 읽기

Python 3.11부터 기본 내장된 tomllib 라이브러리를 사용하여 TOML 파일을 파이썬 딕셔너리로 쉽게 변환할 수 있습니다.

# main.py

import tomllib

# 'rb' (read binary) 모드로 설정 파일을 엽니다.
try:
    with open("config.toml", "rb") as f:
        config = tomllib.load(f)

    # 딕셔너리처럼 설정값에 접근합니다.
    db_url = config["database"]["url"]
    api_key = config["api_keys"]["google_api_key"]

    print(f"데이터베이스 URL: {db_url}")
    print(f"Google API 키: {api_key}")

except FileNotFoundError:
    print("오류: config.toml 파일을 찾을 수 없습니다.")
except KeyError as e:
    print(f"오류: 설정 파일에 {e} 키가 존재하지 않습니다.")

📊 요약 테이블

구분 파일 예시 주요 목적 연동 주체 핵심 명령어 / 함수
프로젝트 관리 pyproject.toml 의존성 패키지 및 프로젝트 정보 정의 uv uv venv, uv pip install .
애플리케이션 설정 config.toml (자유 작명) API 키, DB 정보 등 코드와 분리할 설정 관리 Python tomllib.load()
반응형
반응형
파이썬 Ellipsis(...)와 pass 완벽 설명

파이썬 Ellipsis(...)pass 완벽 설명

1. Ellipsis (...)란?

  • 파이썬의 내장 상수로, 세 개의 점(...)으로 표현합니다.
  • 타입은 EllipsisType이며, type(...)을 하면 EllipsisType이 나옵니다.
  • "구현 예정", "생략", "아직 작성하지 않음"의 의미로 자주 사용합니다.
  • 슬라이스, 추상 메서드, 타입 힌트 등에서 활용됩니다.

기본 예시

def foo():
    ...  # 아직 구현하지 않음

print(foo())  # Ellipsis 객체(...)가 반환됨
print(type(...))  # 

활용 예시

  • 추상 메서드/구현 예정 함수
class MyBase:
    def must_implement(self):
        ...  # 구현은 서브클래스에서
  • 슬라이스에서의 ...
import numpy as np
arr = np.arange(27).reshape(3, 3, 3)
print(arr[..., 0])  # 다차원 배열에서 모든 축을 의미
  • 타입 힌트에서의 ...
from typing import Callable
f: Callable[..., int]  # 임의의 인자, int 반환

주의사항

  • 함수 본문에 ...만 쓰면, 함수가 Ellipsis 객체를 반환합니다.
  • 실제 아무 동작도 하지 않으려면 pass를 사용하세요.

2. pass란?

  • 파이썬의 아무 동작도 하지 않는 문장입니다.
  • 함수, 클래스, if, for 등 코드 블록이 필요하지만 실제로는 아무것도 하지 않을 때 사용합니다.
  • 실행해도 아무런 값도 반환하지 않고, 부작용도 없습니다.

기본 예시

def foo():
    pass

class MyClass:
    pass

비교: ... vs pass

  • pass: 아무 동작도 하지 않음(값 반환 X)
  • ...: Ellipsis 객체를 반환(값 있음)
def f1():
    pass

def f2():
    ...

print(f1())  # None
print(f2())  # Ellipsis

3. 언제 사용하나?

  • 임시로 함수/클래스/메서드의 본문을 비워둘 때: pass 또는 ...
  • 슬라이스, 타입 힌트, 추상 메서드 등 특별한 의미가 필요할 때: ...

4. 참고 자료

TIP: pass는 "아무것도 하지 않음"을, ...는 "구현 예정/생략/특수 의미"를 나타낼 때 사용하세요.
반응형

+ Recent posts