Skip to content
This page has been auto-translated and may contain errors.View in English

변수와 타입

모든 프로그램은 무언가를 기억해야 합니다. 퀴즈는 플레이어의 이름을 기억해야 하고, 게임은 현재 점수를 기억해야 하며, 날씨 스크립트는 확인 중인 도시를 기억해야 합니다. Python은 이를 위해 변수를 사용합니다. 값에 붙이는 이름으로, 프로그램 전체에서 그 값을 사용할 수 있게 합니다.

변수는 값을 가리키는 이름입니다. Python은 =의 오른쪽에 있는 객체에 이름을 묶고, 언제든지 다시 묶을 수 있습니다. 타입은 이름이 아니라 값에 살아있습니다.

Python의 변수는 **이름 바인딩**입니다. 즉, 객체(메모리에 Python이 보관하는 어떤 값, 예를 들어 문자열이나 숫자)를 가리키는 이름이며, 값 자체를 담은 라벨이 붙은 상자가 아닙니다. 타입은 이름이 아니라 객체에 속하므로, 한 이름이 한 줄에서 str을 가리키고 다음 줄에서 int를 가리킬 수 있으며 오류가 발생하지 않습니다. 이 자유를 동적 타이핑이라 부릅니다. 이름에 대한 제약이 없어서 어떤 것이든 가리킬 수 있다는 뜻입니다.

python
player_name = "민지"
score = 0
city = "서울"

세 줄, Python이 이제 기억해야 할 세 가지입니다. 각 줄마다 Python은 오른쪽의 값을 먼저 계산한 다음 왼쪽 이름으로 저장합니다. 나중에 그 이름을 사용하면 Python이 값을 돌려줍니다.

각 줄이 하나의 바인딩을 만듭니다. 왼쪽의 이름이 오른쪽의 객체를 가리킵니다. Python은 오른쪽을 먼저 계산한 후에 바인딩을 만듭니다.

각 할당은 현재 범위(그 이름이 보이는 코드 영역, 보통은 작업 중인 함수나 파일)에서 이름을 바인딩합니다. Python은 항상 오른쪽 전체를 계산한 후에 바인딩합니다. 정확히 이 이유 때문에 a, b = b, a는 한 줄에서 두 값을 교환합니다. 오른쪽이 먼저 완전히 계산되고, 그 후에 두 이름이 결과를 가리킵니다.

값 저장하기

= 기호는 수학 시간에서 온 사람들을 거의 항상 헷갈리게 합니다. Python에서 =는 "같다"는 뜻이 아닙니다. **이 값을 이 이름으로 저장하라**는 뜻입니다.

python
city = "서울"

city"서울"을 얻습니다. Python에 "서울"을 기억하고 city라고 레이블을 붙이라고 말하는 것입니다.

변수의 값은 언제든지 바꿀 수 있습니다. Python은 가장 최근 값을 사용합니다.

python
score = 0
score = 10   # score는 이제 10
score = 15   # score는 이제 15

=할당입니다. 현재 범위에서 이름을 객체에 바인딩합니다. 변수를 업데이트하는 표준 약식 표기법은 **증강 할당**입니다.

python
score = 0
score += 10   # 같음: score = score + 10
score *= 2    # 같음: score = score * 2

여러 이름을 한 번에 바인딩할 수도 있습니다.

python
x, y, z = 1, 2, 3
a = b = 0        # 둘 다 0부터 시작

할당은 이름을 객체에 가리킵니다. 절대로 값을 새 컨테이너에 복사하지 않습니다. 그래서 두 이름이 같은 객체를 가리킬 수 있습니다.

python
a = "hello"
b = a
print(id(a) == id(b))   # True (두 이름이 한 객체를 가리킴)

b = "world"             # b가 새 객체로 다시 바인딩됨
print(id(a) == id(b))   # False
print(a)                # 여전히 "hello": b를 다시 바인딩해도 a는 영향 없음

id()는 객체의 정체성을 반환합니다. 즉, 객체가 존재하는 동안 그 객체에만 고유한 번호입니다. ID가 같다는 것은 "정확히 같은 객체"라는 뜻이지, 같은 값을 가진 두 객체가 아닙니다. 가리킴과 복사의 차이는 지금은 무시하고 싶을지 모르지만, 가변 객체(제자리에서 바꿀 수 있는 것, 예를 들어 리스트)를 다룰 때 문제가 생깁니다. 두 이름이 한 리스트를 가리키면, 어느 이름으로든 변경하면 그 변경이 둘 다에서 보입니다. 리스트와 딕셔너리는 이를 나중 장에서 구체적으로 보여줍니다.

타입 주석은 이름이 보유할 것으로 예상하는 타입을 기록합니다. 코드를 실행하지 않고 읽는 도구(타입 체커와 편집기)를 위한 메모이며, Python은 프로그램 실행 중에 무시합니다.

python
name: str = "민지"
score: int = 0
ratio: float = 0.85
Juno값 저장하기=는 수학 시간 "같다"가 아니라 "이 값을 이 이름으로 보관하라"는 뜻입니다. 언제든지 바꿀 수 있고 Python이 가장 최신 값을 유지합니다. 선언도 설정도 필요 없고, 이름을 붙이면 그냥 존재합니다. 이걸 과하게 생각하는 데 정말 오래 걸렸어요.
Juno값 저장하기=는 이름을 값에 가리킵니다. 언제든 다시 가리킬 수 있습니다. 이름이 레이블이고 값이 물건입니다. 그게 전부입니다.
Juno값 저장하기=는 값을 상자에 넣는 게 아니라 이름을 객체에 묶습니다. 다시 할당하면 그냥 이름만 옮길 뿐, 예전 객체는 그대로입니다. 리스트가 나타나기 전에 이것을 기억하세요. 아니면 두 이름이 조용히 하나를 공유하고 있는 걸 나중에 알게 됩니다.

변수 이름 짓기

이름은 당신이 선택합니다. Python은 몇 가지 엄격한 규칙이 있고, 커뮤니티는 처음부터 따를 가치가 있는 관례를 따릅니다. 명확한 이름은 코드를 나중에 읽기 쉽게 합니다. 암호 같은 이름은 고통을 초래합니다.

Python은 식별자 구문의 작은 집합만 강제합니다. 그 외에는 PEP 8 관례가 모든 Python 코드베이스와 도구에서 사실상 표준입니다.

Python이 식별자(이름의 기술 용어)에 대해 실제로 강제하는 규칙은 최소한입니다. 나머지는 PEP 8이라 부르는 Python의 공식 스타일 가이드입니다. 인터프리터(코드를 실행하는 프로그램)는 강제하지 않지만, 린터(스타일 문제와 가능한 버그를 표시하는 도구), 타입 체커, 모든 전문 코드베이스는 이를 기대합니다. 이에 거슬리면 코드를 다음에 읽을 사람에게만 마찰을 일으킵니다.

Python이 강제하는 규칙:

  • 문자, 숫자, 언더스코어만 가능합니다. 공백이나 하이픈은 안 됩니다.
  • 문자나 언더스코어로 시작해야 합니다. 숫자로 시작할 수 없습니다.
  • 대소문자를 구분합니다. score, Score, SCORE는 세 개의 다른 변수입니다.

모두가 따르는 관례(PEP 8):

대상스타일예시
변수와 함수snake_caseuser_name, total_price
상수UPPER_SNAKE_CASEMAX_RETRIES, BASE_URL
클래스PascalCaseUserAccount, DataLoader
python
# 명확한 이름, 한눈에 읽을 수 있음
user_name = "민지"
total_price = 49.99
is_logged_in = True
MAX_RETRIES = 3

# 이런 건 한 시간 안에 후회할 겁니다
x = "민지"
tp = 49.99
b = True

일찍 알면 좋은 함정 하나: 변수 이름을 list, input, type, print 같은 Python 내장 함수로 지으면 안 됩니다. Python이 허용하지만, 그 범위의 나머지에서 내장 함수를 조용히 망칠 것이고, 그 결과로 나타나는 오류는 추적하기 어렵습니다.

Python의 내장 함수를 가리지 마세요. list, type, input, print, str에 할당하면 경고 없이 그 범위의 나머지에서 내장 함수를 덮어씁니다. 조용한 버그로, 찾기 어려울 수 있습니다.

UPPER_SNAKE_CASE는 관례이지, 강제가 아닙니다. Python은 나중에 MAX_RETRIES = 99로 다시 할당하는 것을 막지 않습니다. 다른 개발자들을 위한 신호일 뿐입니다.

가리킴은 Python이 이미 제공하는 것과 일치하는 자신의 이름을 만드는 것입니다(list 같은). Python이 이름을 찾을 때, 로컬 이름을 먼저 확인한 후 자신의 내장 함수를 확인하므로, 당신의 버전이 우선이고 실제 list는 그 시점부터 숨겨집니다. 여전히 builtins.list로 접근할 수 있지만, 일반 코드는 더 이상 보지 못합니다. 상수에 대해서는, UPPER_SNAKE_CASE는 시각적 신호일 뿐입니다. Python은 기꺼이 다시 할당할 것입니다. 도구가 실제로 강제할 수 있는 상수를 원하면, typing.Final로 주석을 달아서 이름을 "다시 할당하려고 의도하지 않았다"고 표시하면 타입 체커가 이를 위반할 때 플래그를 지울 것입니다.

Juno변수 이름 짓기 문자, 숫자, 언더스코어, 문자나 언더스코어로 시작하세요. snake_case를 고집하면 당신은 완벽합니다. 제 한 가지 초보자 실수: 변수를 listprint로 부르지 마세요. Python이 허용하면 나중에 경고 없이 모든 게 이상해집니다.
Juno변수 이름 짓기snake_case 이름, UPPER_SNAKE_CASE 상수, 모든 도구가 기대합니다. 그리고 listprint로 이름을 지으면 안 됩니다. 내장 함수를 조용히 망칠 것입니다.
Juno변수 이름 짓기 인터프리터는 거의 이름을 강제하지 않지만, 모든 린터는 강제합니다. 그래서 snake_case에 거슬리면 그냥 고통받게 됩니다. 진짜 함정은 list 같은 내장을 가리키는 것입니다. 조용히 깨지고, 당신이 한 곳과 먼 곳에서 일어납니다.

저장할 수 있는 것

Python은 거의 모든 프로그램에서 사용할 네 가지 타입을 가지고 있습니다. Python은 값을 어떻게 썼는지를 보고 타입을 파악합니다. 타입을 명시적으로 선언할 필요가 없습니다.

Python은 리터럴 구문에서 타입을 추론합니다. 이 네 가지 타입은 기본 값 공간을 다룹니다. 언어의 모든 것이 이 위에 만들어집니다.

Python의 모든 값은 완전한 객체입니다. 리터럴(코드에 직접 쓴 값, 예를 들어 42"hi")도 포함합니다. 객체라는 것은 값이 자신의 메서드(그 값에 붙어있는 함수)를 가진다는 뜻입니다. 그래서 "hi".upper()(3).bit_length()는 감싸거나 풀지 않고 리터럴에 직접 작동합니다. 이에 대해 생각할 일은 거의 없고, 그것이 요점입니다. 아래의 네 가지 타입은 거의 모든 프로그램에서 사용할 것입니다.

텍스트(str)

모든 텍스트는 따옴표(단일 또는 이중)로 감쌉니다. 따옴표는 Python에 문자 그대로의 문자를 의도한 것이고, 변수 이름이 아님을 알립니다. 한 번 만들어진 문자열은 제자리에서 바뀔 수 없습니다. 문자열 장에서 문자열로 할 수 있는 모든 것을 다룹니다.

python
player_name = "민지"
city = "서울"
message = '게임 오버'

텍스트에 아포스트로피가 포함되면, 이스케이프할 필요가 없도록 이중 따옴표를 사용하세요.

python
note = "It's a great day"
note = 'It\'s a great day'   # 같은 결과, 이스케이프 사용

문자열은 단일 또는 이중 따옴표로 모든 텍스트를 담습니다. 그들은 불변입니다. 문자열을 제자리에서 수정하는 작업은 없습니다. 모든 변환은 새로운 것을 반환합니다. 이것은 성능에 중요합니다. 루프 안에서 반복적인 +는 매 단계마다 새 문자열 객체를 만듭니다. 문자열 장에서 효율적인 대안을 다룹니다.

python
player_name = "민지"
city = "서울"
note = "It's a great day"

str불변 Unicode 코드 포인트(불변이란 만들어진 후 절대 바뀔 수 없다는 뜻이고, 코드 포인트는 문자 자체지, 저장되는 원본 바이트가 아닙니다)의 수열입니다. 이것이 len("café")가 5가 아니라 4인 이유입니다. 문자열은 변할 수 없기 때문에 해시 가능하고, 딕셔너리 키나 집합 멤버(절대 바뀌지 않는 값)로 사용될 수 있습니다. 이에서 나오는 실제로 사용할 규칙이 하나 있습니다. 문자열을 ==(같은 문자)로 비교하세요. is(메모리에서 같은 객체)는 절대 사용하지 마세요. 두 같은 문자열이 한 객체를 공유하는지는 구현 세부사항이라 신뢰할 수 없습니다.

python
player_name = "민지"
city = "서울"
note = "It's a great day"
Juno텍스트(str) 텍스트는 따옴표로 감싸세요. 단일 또는 이중, 선택은 당신 것입니다. 한 번 존재하면 제자리에서 바꿀 수 없고, 그게 괜찮습니다. 문자열을 편집하는 것처럼 보이는 모든 것은 실제로 새로운 것을 돌려줍니다.
Juno텍스트(str) 문자열은 불변입니다. 제자리에서 편집하는 것은 없고, 항상 새 문자열을 돌려받습니다. 메서드를 연결하기 시작할 때를 생각해두세요.
Juno텍스트(str) 불변 Unicode 수열이므로 len("café")는 4이고 문자열이 딕셔너리 키로 작동합니다. 실제로 사용할 부분: ==으로 비교하세요. is는 절대 아닙니다.

정수(int)

정수는 따옴표나 소수점 없이 쓰입니다. Python은 이를 정수라 부릅니다. 원하는 만큼 클 수 있습니다. Python은 아무런 특별한 노력 없이 임의로 큰 숫자를 처리합니다.

python
score = 0
age = 28
population = 8_100_000_000   # 언더스코어는 읽기 쉽게 하는 것일 뿐

정수는 따옴표나 소수점 없이 쓰입니다. Python 정수는 임의 정밀도입니다. C나 Java의 32비트 또는 64비트 고정 크기 정수와 달리, 어떤 값이든 담도록 커집니다. 숫자 리터럴의 언더스코어는 미적이며 Python이 무시합니다.

python
score = 0
age = 28
population = 8_100_000_000

기억할 두 가지가 있습니다. 첫째, Python의 int임의 정밀도입니다. RAM이 담을 수 있는 어떤 정수든 담도록 커지므로, 고정 크기 정수를 가진 언어에서 마주치는 오버플로우(래핑 또는 오류)를 설계할 필요가 없습니다. 둘째, 숫자를 ==(같은 값)으로 비교하세요. is(같은 객체)는 절대 사용하지 마세요. 두 같은 정수가 같은 객체인지는 구현 세부사항입니다. CPython(표준 Python)은 작은 정수를 재사용하므로 id(1) == id(1)True이지만, 더 큰 숫자에서는 조용히 성립 안 하므로 절대 이것에 의존하지 마세요.

python
score = 0
age = 28
population = 8_100_000_000
Juno정수(int) 정수, 따옴표 없음, 소수점 없음. 최고의 부분, Python 정수는 원하는 만큼 커져서 이상한 오버플로우가 없습니다. 8_100_000_000의 언더스코어는 읽기 위함일 뿐입니다.
Juno정수(int) 정수는 임의 정밀도이므로 오버플로우 걱정이 없습니다. 숫자에 언더스코어를 많이 사용하세요.
Juno정수(int) 정수는 RAM을 다할 때까지 커져서 오버플로우는 문제 없습니다. 지킬 한 가지 습관: 숫자를 ==으로 비교하세요. is는 아닙니다. 정체성은 캐싱 트릭일 뿐, 거기 의존하지 마세요.

소수(float)

소수점이 있는 모든 숫자는 float입니다. 대부분의 계산에서 예상대로 작동합니다. 한 가지 알아야 할 것: 어떤 소수 값은 이진수로 정확히 저장될 수 없어서 작은 반올림 오류가 생길 수 있습니다.

python
price = 4.99
temperature = 36.6

0.1 + 0.2   # 0.30000000000000004

일반 작업에서는 이것이 거의 중요하지 않습니다. 센트 미만의 금액이 중요한 금융 계산의 경우, Python은 올바르게 처리하는 decimal 모듈을 가지고 있습니다. 이는 숫자 장에서 다룹니다.

소수점이 있는 모든 숫자는 float가 됩니다. Python float는 배정밀도입니다. 약 15~17 자리의 유효 숫자이며, 이진수로 저장됩니다. 그 이진 저장이 잘 알려진 함정입니다. 0.1 + 0.20.30000000000000004이며, Python 버그가 아니라 이진수가 소수를 어떻게 나타내는지의 결과입니다. 돈이나 정확한 소수가 중요한 곳에서는, Python의 decimal 모듈을 사용하세요. 숫자 장에서 다룹니다.

python
price = 4.99
temperature = 36.6

float는 이진수(2진법)로 저장되고, 대부분의 소수 분수, 분모가 2의 거듭제곱이 아닌 것(예: 1/10)은 이진수로 정확히 쓸 수 없습니다. 이것이 0.1 + 0.20.30000000000000004가 되는 곳에서 비롯됩니다. 프로덕션에서 중요한 규칙: float를 돈에 절대 사용하지 마세요. 정확한 같음을 확인할 것도 절대 아닙니다. 정확한 10진수 산술이 필요할 때는 decimal.Decimal을 사용하세요. 정확한 비율에는 fractions.Fraction을 사용하세요. 둘 다 Python의 표준 라이브러리(Python과 함께 묶여있는 도구)에 포함되어 있으며, 모듈 장에서 다룹니다.

python
price = 4.99
temperature = 36.6
Juno소수(float) 소수점이 있으면 float이고, 일상 업무에는 좋습니다. 모두가 한 번씩 마주치는 고전 함정: 0.1 + 0.20.30000000000000004를 줍니다. 버그가 아니라 이진수입니다. 돈에는 decimal.Decimal을 사용하세요.
Juno소수(float) float는 이진수이므로 어떤 소수는 정확하지 않습니다. 0.1 + 0.2는 정확히 0.3이 아닙니다. 대부분의 수학에는 괜찮고, 돈에는 절대 아닙니다. 정확해야 할 때는 decimal.Decimal을 사용하세요.
Juno소수(float) float는 표류합니다. 그래서 0.1 + 0.2는 깨진 것처럼 보입니다. 규칙: 돈이나 정확한 같음 확인에는 float를 사용하지 마세요. 정확한 10진수는 decimal.Decimal, 비율은 fractions.Fraction.

참/거짓(bool)

어떤 것들은 켜졌거나 꺼져있습니다. Python은 이를 위해 부울을 사용합니다. 정확히 두 값, TrueFalse입니다. 지금은 작아 보이지만, 프로그램의 모든 조건과 분기는 부울에서 실행됩니다.

python
is_logged_in = True
has_errors = False

Python은 또한 어떤 값들을 조건에서 사용할 때 False인 것처럼 취급합니다. 0, 0.0, "", None(Python의 "여기 값이 없다")은 모두 False처럼 행동합니다. 다른 모든 것은 True처럼 행동합니다. 이는 제어 흐름 장에서 유용해집니다.

bool은 정확히 True 또는 False를 담습니다. 비교로 반환되고 조건으로 소비됩니다. Python은 더 넓은 truthyfalsy 값의 집합을 가지고 있습니다. 0 값, 빈 컨테이너, None은 falsy입니다. 다른 모든 것은 truthy입니다. 유용한 세부사항 하나: boolint의 서브클래스이므로 True + True2로 계산됩니다.

python
is_logged_in = True
has_errors = False

boolint 위에 만들어집니다(서브클래스입니다. 즉, 특화된 종류의 int입니다). TrueFalse는 유일하게 존재하는 두 bool 객체이며, 각각 1과 0의 값을 가집니다. 조건에서, falsy 값(거짓으로 세는 것)은 0들(0, 0.0), 빈 컨테이너("", [], (), {}), None, False 자체입니다. 다른 모든 것은 truthy입니다. 당신의 클래스는 __bool__ 또는 __len__을 정의하여(dunder 메서드, 이중 언더스코어로 이름 붙은, Python이 예/아니오 답이 필요할 때 호출하는) 그들의 truthiness를 결정할 수 있습니다. 그리고 boolint이기 때문에, isinstance(True, int)True이며, 이는 타입을 확인하는 코드에서 당신을 놀라게 할 수 있습니다.

python
is_logged_in = True
has_errors = False
Juno참/거짓(bool) 두 값, TrueFalse, 그리고 당신이 쓸 모든 if 뒤에 있습니다. 재미있는 부분: 0, "", [], None은 모두 False로 세어집니다. 다른 모든 것은 True입니다.
Juno참/거짓(bool)bool은 비교에서 True/False입니다. Python은 또한 truthy와 falsy를 가집니다. 빈 것, 0, None은 falsy입니다. 그래서 if my_list:가 그렇게 잘 읽힙니다.
Juno참/거짓(bool)bool은 몰래 int이므로 isinstance(True, int)True입니다. 타입 확인 중에 언젠가 당신을 놀라게 할 것입니다. Falsy는 0, 빈 것, None입니다. 커스텀 객체는 __bool__이나 __len__으로 자신의 truthiness를 고릅니다.

타입 확인과 변환

값의 타입이 확실하지 않을 때, type()이 말해줍니다. 값이 특정 타입인지 확인하려면, isinstance()이 더 신뢰할 수 있는 도구입니다.

python
print(type("hello"))   # <class 'str'>
print(type(42))        # <class 'int'>
print(type(3.14))      # <class 'float'>
print(type(True))      # <class 'bool'>

isinstance(42, int)    # True
isinstance("hi", str)  # True

type()은 객체의 정확한 타입을 반환합니다. 자신의 코드에서 타입을 확인할 때는, isinstance()가 더 나은 선택입니다. 상속을 처리하고, type() 비교는 그렇지 않습니다.

python
print(type(42))          # <class 'int'>
isinstance(True, int)    # True   (bool은 int의 서브클래스)
type(True) == int        # False  (정확히 일치만, 서브클래스 없음)

type(x)x의 정확한 타입을 줍니다. isinstance(x, T)는 더 합니다. MRO(메서드 해석 순서, 클래스가 만들어지는 부모 타입의 줄인 상속 체인을 Python이 검색하는 정렬된 클래스 목록으로, x.__class__.__mro__로 노출됨)를 걸어서, 부모 타입도 True를 반환합니다. 이것이 isinstance(True, int)True(부울은 정수의 종류)이지만 type(True) == intFalse(정확히 일치 확인)인 이유입니다. 실제 코드에서, isinstance()를 당신의 타입 가드(값이 사용하기 전에 기대하는 타입인지 확인하는 확인)로 사용하세요.

python
isinstance(True, int)    # True
type(True) == int        # False

Python은 타입을 자동으로 혼합하지 않습니다. 문자열과 숫자를 연결하면 TypeError가 발생합니다.

python
score = 42
print("Your score is " + score)        # TypeError
print("Your score is " + str(score))   # 작동

타입 이름을 함수로 사용하여 명시적으로 변환하세요.

호출결과
str(42)"42"
int(3.9)3 (내림, 반올림 아님)
float("3.14")3.14
int("3.14")ValueError: 소수 문자열을 정수로 직접 변환할 수 없음
int(float("3.14"))3 (먼저 float로 변환, 그 다음 정수로)
bool(0) / bool("")False
Juno타입 확인과 변환type()은 무언가가 무엇인지 알려줍니다. isinstance()는 주어진 타입인지 확인합니다. 그리고 Python은 문자열과 숫자를 붙이지 않으므로 str()이나 int()로 먼저 변환하세요. 모두가 한 번씩 실패합니다.
Juno타입 확인과 변환type() ==보다 isinstance()를 사용하세요. 상속을 존중합니다. 변환은 항상 명시적입니다. 따라서 문자열과 숫자를 연결하기 전에 변환하세요.
Juno타입 확인과 변환isinstance()은 당신의 타입 가드이고, 클래스 트리를 따릅니다. type(x) == T는 정확히 일치합니다. 변환은 의도적으로 명시적입니다. int("3.14")는 추측하기보다 발생시키기를 선호하므로, 먼저 float를 거쳐야 합니다.

실제 사용

네 가지 타입이 작은 스크립트에서 함께 작동합니다. 출력 줄은 f-문자열을 사용하여 텍스트에 값을 포함합니다. 열기 따옴표 앞에 f를 붙이고 변수를 {}로 감싸세요. Python이 변수의 실제 값으로 바꿉니다. 다음 장에서 이를 제대로 배웁니다.

python
player_name = "민지"
level = 3
accuracy = 0.94
is_premium = True

print(f"{player_name} is on level {level} with {accuracy:.0%} accuracy.")
print(f"Premium account: {is_premium}")

타입이 중요한 이유는 level + 1은 작동하지만 player_name + 1은 그렇지 않기 때문입니다. 각 변수는 정확히 한 종류의 것을 담습니다. Python은 자동으로 이들을 섞지 않습니다.

네 가지 타입 모두가 있는 현실적인 config 블록. 상수는 런타임 상태와 분리됩니다. f"..."f-문자열입니다. {}안의 모든 식은 런타임에 계산되어 출력에 포함됩니다. 출력과 입력 장에서 완전히 다룹니다.

python
BASE_URL = "https://api.example.com"
MAX_RETRIES = 3
DEBUG = False

user_name = "민지"
request_count = 0
last_response = None

request_count += 1
print(f"[{request_count}] {BASE_URL} | debug={DEBUG}")

None은 "아직 값이 없다"의 표준 자리 표시자입니다. 그 타입은 NoneType이고 조건에서 falsy처럼 행동합니다. 프로그램 후반에 의미 있기 전까지 변수의 기본값으로 사용하세요.

같은 config이지만, 이제 인라인 타입 주석이 있습니다. 주석은 이름이 보유할 것으로 예상하는 타입을 기록합니다. 타입 체커와 편집기(IDE)를 위해 존재하고, Python은 프로그램 실행 중에 무시합니다.

python
BASE_URL: str = "https://api.example.com"
MAX_RETRIES: int = 3
DEBUG: bool = False

user_name: str = "민지"
request_count: int = 0
last_response: str | None = None

str | None합집합 타입입니다. Python 3.10에서 추가되었습니다. 값이 문자열이거나 None이라고 말합니다. 구 버전에서는 typing 모듈에서 import한 Optional[str]로 같은 것을 씁니다. str | None 형식이 최소 버전을 허용하는 최신 Python에서 선호할 것입니다.