Created at : 2024-11-18 01:45
Auther: Soo.Y


πŸ“λ©”λͺ¨

Python 3.11

1. μ˜ˆμ™Έ κ·Έλ£Ήκ³Ό except* ꡬ문 (PEP 654)

비동기 ν”„λ‘œκ·Έλž˜λ°μ΄λ‚˜ 병렬 μ²˜λ¦¬μ—μ„œ μ—¬λŸ¬ μ˜ˆμ™Έκ°€ λ™μ‹œμ— λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€. Python 3.11μ—μ„œλŠ” μ΄λŸ¬ν•œ μ—¬λŸ¬ μ˜ˆμ™Έλ₯Ό ν•˜λ‚˜μ˜ μ˜ˆμ™Έ 그룹으둜 묢을 수 μžˆλŠ” ExceptionGroup이 λ„μž…λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

# μ—¬λŸ¬ μ˜ˆμ™Έλ₯Ό ν¬ν•¨ν•œ μ˜ˆμ™Έ κ·Έλ£Ή 생성
exc_group = ExceptionGroup("μ—¬λŸ¬ μ—λŸ¬ λ°œμƒ", [
    ValueError("잘λͺ»λœ κ°’μž…λ‹ˆλ‹€."),
    TypeError("νƒ€μž…μ΄ λ§žμ§€ μ•ŠμŠ΅λ‹ˆλ‹€."),
    ZeroDivisionError("0으둜 λ‚˜λˆŒ 수 μ—†μŠ΅λ‹ˆλ‹€.")
])
 
try:
    raise exc_group
except* ValueError as e:
    print(f"ValueError 처리: {e}")
except* TypeError as e:
    print(f"TypeError 처리: {e}")
except* Exception as e:
    print(f"기타 μ˜ˆμ™Έ 처리: {e}")
  • except*ꡬ문은 μ˜ˆμ™Έ κ·Έλ£Ήμ—μ„œ ν•΄λ‹Ή μ˜ˆμ™Έ νƒ€μž…μ— λ§€μΉ­λ˜λŠ” μ˜ˆμ™Έλ“€μ„ μ²˜λ¦¬ν•©λ‹ˆλ‹€.
  • e.exceptionsλŠ” 처리된 μ˜ˆμ™Έλ“€μ˜ 리슀트λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.
  • μ²˜λ¦¬λ˜μ§€ μ•Šμ€ μ˜ˆμ™ΈλŠ” λ‹€μ‹œ μ˜ˆμ™Έ 그룹으둜 λ¬Άμ—¬ μ „νŒŒλ©λ‹ˆλ‹€.
  • 이 κΈ°λŠ₯은 λ³΅μž‘ν•œ μ˜ˆμ™Έ 처리λ₯Ό λ‹¨μˆœν™”ν•˜κ³ , 비동기 μ½”λ“œμ—μ„œμ˜ μ˜ˆμ™Έ 관리λ₯Ό λ”μš± 효율적으둜 λ§Œλ“€μ–΄μ€λ‹ˆλ‹€.

2. μ„±λŠ₯ ν–₯상

Python 3.11은 λ‚΄λΆ€ μ΅œμ ν™”λ₯Ό 톡해 μ „λ°˜μ μœΌλ‘œ μ‹€ν–‰ 속도λ₯Ό 크게 ν–₯μƒμ‹œμΌ°μŠ΅λ‹ˆλ‹€. λŒ€λΆ€λΆ„μ˜ μ½”λ“œμ—μ„œ 10~60%의 μ„±λŠ₯ κ°œμ„ μ„ κΈ°λŒ€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import time
 
def compute():
    total = 0
    for i in range(1_000_000):
        total += i
    return total
 
start_time = time.time()
result = compute()
end_time = time.time()
 
print(f"κ²°κ³Ό: {result}")
print(f"μ‹€ν–‰ μ‹œκ°„: {end_time - start_time} 초")

3. asyncio λͺ¨λ“ˆμ˜ κ°œμ„ : TaskGroup 클래슀

비동기 μž‘μ—…μ„ κ·Έλ£Ήν™”ν•˜κ³  κ΄€λ¦¬ν•˜κΈ° μœ„ν•œ TaskGroup ν΄λž˜μŠ€κ°€ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

import asyncio
 
async def task(name, delay):
    await asyncio.sleep(delay)
    print(f"μž‘μ—… {name} μ™„λ£Œ")
 
async def main():
    async with asyncio.TaskGroup() as tg:
        tg.create_task(task("A", 2))
        tg.create_task(task("B", 1))
    print("λͺ¨λ“  μž‘μ—… μ™„λ£Œ")
 
asyncio.run(main())

좜λ ₯:

μž‘μ—… B μ™„λ£Œ
μž‘μ—… A μ™„λ£Œ
λͺ¨λ“  μž‘μ—… μ™„λ£Œ
  • asyncio.TaskGroup()을 μ‚¬μš©ν•˜λ©΄ μ—¬λŸ¬ 비동기 μž‘μ—…μ„ ν•œ 그룹으둜 λ¬Άμ–΄ 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • async with 블둝이 μ’…λ£Œλ  λ•ŒκΉŒμ§€ κ·Έλ£Ή λ‚΄μ˜ λͺ¨λ“  μž‘μ—…μ΄ μ™„λ£Œλ  λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦½λ‹ˆλ‹€.
  • μž‘μ—… 쀑 ν•˜λ‚˜μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ κ·Έλ£Ή λ‚΄μ˜ λ‹€λ₯Έ μž‘μ—…λ“€λ„ μ·¨μ†Œλ©λ‹ˆλ‹€.

4. νƒ€μž… νžŒνŒ… κ°œμ„ 

4.1 Selfνƒ€μž… (PEP 673)

클래슀 λ©”μ„œλ“œμ˜ λ°˜ν™˜ νƒ€μž…μ„ μ •μ˜ν•  λ•Œ Self νƒ€μž…μ„ μ‚¬μš©ν•  수 있게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” λ©”μ„œλ“œ μ²΄μ΄λ‹μ΄λ‚˜ μ„œλΈŒν΄λž˜μ‹±μ—μ„œ νƒ€μž… νžŒλ”©μ„ λ”μš± μ •ν™•ν•˜κ²Œ λ§Œλ“€μ–΄μ€λ‹ˆλ‹€.

from typing import Self
 
class Shape:
    def set_color(self, color: str) -> Self:
        self.color = color
        return self
 
class Circle(Shape):
    def set_radius(self, radius: float) -> Self:
        self.radius = radius
        return self
 
circle = Circle().set_color("red").set_radius(5.0)
  • set_color와 set_radiusλ©”μ„œλ“œλŠ” Selfνƒ€μž…μ„ λ°˜ν™˜ν•˜μ—¬ λ©”μ„œλ“œ 체이닝이 κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.
  • SelfλŠ” ν˜„μž¬ μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ„ μ˜λ―Έν•˜λ―€λ‘œ, μ„œλΈŒν΄λž˜μ‹± μ‹œμ—λ„ μ •ν™•ν•œ νƒ€μž… 정보λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.

4.2 typing.LiteralString (PEP 675)

λ³΄μ•ˆκ³Ό κ΄€λ ¨λœ ν•¨μˆ˜μ— λ¦¬ν„°λŸ΄ λ¬Έμžμ—΄λ§Œ ν—ˆμš©ν•˜λ„λ‘ LiteralString νƒ€μž…μ΄ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

from typing import LiteralString
 
def safe_format(template: LiteralString, /, **kwargs):
    return template.format_map(kwargs)
 
# μ˜¬λ°”λ₯Έ μ‚¬μš©
result = safe_format("μ•ˆλ…•ν•˜μ„Έμš”, {name}λ‹˜!", name="홍길동")
print(result)  # 좜λ ₯: μ•ˆλ…•ν•˜μ„Έμš”, ν™κΈΈλ™λ‹˜!
 
# 잘λͺ»λœ μ‚¬μš©
user_input = "{name}λ‹˜μ΄ λ‘œκ·ΈμΈν–ˆμŠ΅λ‹ˆλ‹€."
# λ‹€μŒ 쀄은 νƒ€μž… κ²€μ‚¬κΈ°μ—μ„œ 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚΅λ‹ˆλ‹€.
# result = safe_format(user_input, name="홍길동")
  • LiteralStringνƒ€μž…μ€ ν•¨μˆ˜ 인자둜 λ¦¬ν„°λŸ΄ λ¬Έμžμ—΄λ§Œ 받도둝 μ œν•œν•©λ‹ˆλ‹€.
  • μ™ΈλΆ€ μž…λ ₯μ΄λ‚˜ λ³€μˆ˜μ— μ €μž₯된 λ¬Έμžμ—΄μ„ 인자둜 μ „λ‹¬ν•˜λ©΄ νƒ€μž… κ²€μ‚¬κΈ°μ—μ„œ 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚΅λ‹ˆλ‹€.
  • μ΄λŠ” 포맷 λ¬Έμžμ—΄ 곡격과 같은 λ³΄μ•ˆ 취약점을 λ°©μ§€ν•˜λŠ” 데 도움이 λ©λ‹ˆλ‹€.

5. TOML νŒŒμ„œ (tomllib) μΆ”κ°€ (PEP 680)

Python ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ— TOML νŒŒμΌμ„ νŒŒμ‹±ν•  수 μžˆλŠ” tomllib λͺ¨λ“ˆμ΄ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

import tomllib
 
with open('config.toml', 'rb') as f:
    config = tomllib.load(f)
 
print(config)

config.toml파일

[database]
user = "admin"
password = "secret"
host = "localhost"
port = 3306

좜λ ₯

{
'database':
 {
  'user': 'admin',
  'password': 'secret',
  'host': 'localhost',
  'port': 3306
  }
}
  • tomllib.load()λ₯Ό μ‚¬μš©ν•˜μ—¬ TOML ν˜•μ‹μ˜ νŒŒμΌμ„ λ”•μ…”λ„ˆλ¦¬λ‘œ νŒŒμ‹±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 이제 λ³„λ„μ˜ μ™ΈλΆ€ 라이브러리 없이도 TOML νŒŒμΌμ„ μ†μ‰½κ²Œ μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

7 dataclassesλͺ¨λ“ˆμ˜ slots 지원 (PEP 681)

dataclasses.dataclass λ°μ½”λ ˆμ΄λ”μ— slots=Trueμ˜΅μ…˜μ„ μΆ”κ°€ν•˜μ—¬ μžλ™μœΌλ‘œ __slots__λ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

slots을 μ‚¬μš©ν•˜μ§€ μ•Šμ„ 경우

from dataclasses import dataclass
 
@dataclass
class Person:
    name: str
    age: int
 
p = Person(name="John", age=30)
p.new_attr = "Oops!"  # μƒˆλ‘œμš΄ 속성 μΆ”κ°€ κ°€λŠ₯

slots을 μ‚¬μš©ν•œ 경우

from dataclasses import dataclass
 
@dataclass(slots=True)
class Person:
    name: str
    age: int
 
p = Person(name="John", age=30)
# p.new_attr = "Oops!"  # AttributeError λ°œμƒ: 'Person' 객체에 'new_attr' 속성을 μΆ”κ°€ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
slotsλ₯Ό μ‚¬μš©ν•˜λŠ” 이유
  • μ„±λŠ₯ μ΅œμ ν™”: λ§Žμ€ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜κ±°λ‚˜ 속성을 자주 μ ‘κ·Όν•˜λŠ” 경우 μ„±λŠ₯이 ν–₯μƒλ©λ‹ˆλ‹€.
  • λ©”λͺ¨λ¦¬ μ ˆμ•½: λ©”λͺ¨λ¦¬ μ†ŒλΉ„κ°€ κ°μ†Œν•˜μ—¬ λ©”λͺ¨λ¦¬ 효율이 λ†’μ•„μ§‘λ‹ˆλ‹€.
μ œν•œμ‚¬ν•­
  • μœ μ—°μ„± κ°μ†Œ: slotsλ₯Ό μ‚¬μš©ν•˜λ©΄ μ„ μ–Έλœ 속성 외에 μƒˆλ‘œμš΄ 속성을 μΆ”κ°€ν•  수 μ—†κΈ° λ•Œλ¬Έμ— μœ μ—°μ„±μ΄ λ‹€μ†Œ κ°μ†Œν•©λ‹ˆλ‹€.
  • 닀쀑 상속 μ œν•œ: slotsλ₯Ό μ‚¬μš©ν•œ ν΄λž˜μŠ€λŠ” 닀쀑 μƒμ†μ—μ„œ μ œν•œμ΄ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ“œμΆœμ²˜(μ°Έκ³  λ¬Έν—Œ)

Python 3.11 κ³΅μ‹λ¬Έμ„œ


πŸ”—μ—°κ²° λ¬Έμ„œ

Python 3.10