이것저것 라이브러리와 소스를 갖다 써서 프로젝트는 완성했는데, 정작 기본 문법이나 자료형을 아직도 잘 모르겠다. 그래서 공부하는 김에 간단히 정리해서 올려보겠다.

이번 게시물에서는 기본 자료형(Built-in Types)에 대해 간략하게 알아보겠다. (3.8 버전 기준)

Python documentation은 이 링크에서 확인할 수 있다.

 

 

기본 자료형(Built-in Types)의 종류

  • 0. 내장 상수
  • 1. 숫자 (numerics)
  • 2. 시퀀스 (sequences)
  • 3. 매핑 (mappings)
  • 4. 예외 (exceptions)

 

 

0. 내장 상수

내장 상수가 여러개 있다. 그 중 자주 쓰는걸 소개하면 아래와 같다. (나머지는 여기)

  • bool 클래스
    : 후술할 int 클래스의 subclass
    • True
    • False
  • None: NoneType 클래스의 유일한 값

이 상수에 뭔가 다른 값을 덧씌울 수 없다. 덧씌울 경우 SyntaxError를 raise 하게 된다.

 

 

1. 숫자 (numerics)

a = 1 + 2
b = 4 + 5.6
c = 7 + 8j

print(a)	# 3
print(type(a))	# <class 'int'>

print(b)	# 9.6
print(type(b))	# <class 'float'>

print(c)	# (7+8j)
print(type(c))	# <class 'complex'>
  • 정수 (int)
  • 실수 (float)
  • 복소수 (complex)

먼저 정수의 표현범위가 무제한이다. 파이썬 2에서는 정수값 범위에 따라 int, long 여부가 결정되었는데 3은 상관이 없다. 실수는 C의 double과 비슷하다.

복소수는 숫자 뒤에 리터럴 j를 붙이면 된다. 대문자 J도 된다.

\[a = 1+8j ~~ (i 아님)\]

예를 들어 a = 1 + 8j 라고 쓰면 a는 실수부가 1이고 허수부가 8인 1 + 8i가 되는 셈이다.

그런데 문득 궁금해졌다. 왜 i가 아니고 j일까?

 

파이썬 창시자의 복소수 리터럴에 대한 설명

파이썬 창시자의 말로는 'i랑 I, 1이랑 헷갈리지 않느냐', 'V=IR 이런 식으로 공학에서 I를 쓰니까 헷갈리지 않게 j를 쓴거다' 이런식으로 이유를 들었다.

그런데 stackoverflow의 한 유저가 댓글에서 지적했다시피 소문자 i를 써도 무방했을 것 같다. J는 줄(N*m)이기도 하고.

어쨌거나 파이썬 개발자가 바꿀 일 없다니까 파이썬 복소수에서는 j를 쓴다는 걸 기억해두길 바란다.

 

 

2. 시퀀스 (sequences)

시퀀스는 가변(mutable) 시퀀스와 불변(immutable) 시퀀스가 존재한다. 불변 시퀀스는 말 그대로 값을 삭제, 수정할 수 없다. 아래에서 설명하겠다.

세 가지 기본 시퀀스 형이 존재한다.

  • 가변 시퀀스
    • 리스트 (list)
  • 불변 시퀀스
    • 튜플 (tuple)
    • 범위 (range)

 

a = [1, 2]
a.append(0)
a.pop(0)
b = []
c = [3, 4, [5, 6, [7, 8]]]
d = c[1:]

print(a)		# [2, 0]
print(type(b))		# <class 'list'>
print(c[2][2][1])	# 8
print(d)		# [4, [5, 6, [7, 8]]]

먼저 리스트는 가변 시퀀스다. 이건 뭐 쉬우니 설명할 게 없다. 중괄호([, ])를 사용하는 것을 기억하면 된다. 인덱스는 0부터 시작한다. [i:j] 형태로 슬라이싱 할 수 있다.

리스트는 배열로 구현돼있을까? 아니면 링크드 리스트로 구현돼있을까? 구현체에 따라 다르겠지만 CPython에서는 variable length array로 구현돼있다고 한다. 확인은 안해봤지만 다른 구현체도 아마 var-length array로 되어 있을 것이다.

링크드리스트를 사용하고 싶으면 collections.deque 등을 사용해야 한다.

 

a = (1, 2.3, (4, 5+6j))
print(type(a))	# <class 'tuple'>
print(a[0])	# 1

a[0] = 3        # TypeError: 'tuple' object doesn't support item assignment
del(a[0])       # TypeError: 'tuple' object doesn't support item deletion

튜플은 불변 시퀀스로 괄호((, ))를 사용해 생성할 수 있다. 불변 시퀀스이기 때문에 수정이나 삭제를 할 수 없다. 수정하려고 하면 TypeError를 raise한다.

슬라이싱, 인덱싱 등 나머지 속성은 리스트와 똑같다.

 

# class range(stop)
# class range(start, stop[, step])

>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

>>> list(range(0, 30, 5))
[0, 5, 10, 15, 20, 25]

>>> list(range(0, 10, 3))
[0, 3, 6, 9]

>>> list(range(0, -10, -1))
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

>>> list(range(0))
[]

>>> list(range(1, 0))
[]

range 형은 숫자의 불변 시퀀스를 나타낸다. 이때 인자는 모두 정수형이 필요하다. start의 기본값은 0, step의 기본값은 1이다.

 

추가적으로 텍스트, 바이너리 시퀀스가 있다.

  • 텍스트 시퀀스 (string)
  • 바이너리 시퀀스
    • bytes
    • bytearray
    • memoryview
# builtins.py

class str(object):
    """
    str(object='') -> str
    str(bytes_or_buffer[, encoding[, errors]]) -> str
    
    Create a new string object from the given object. If encoding or
    errors is specified, then the object must expose a data buffer
    that will be decoded using the given encoding and error handler.
    Otherwise, returns the result of object.__str__() (if defined)
    or repr(object).
    encoding defaults to sys.getdefaultencoding().
    errors defaults to 'strict'.
    """

파이썬의 문자열 클래스는 str인데 불변 시퀀스임에 주의하자. 작은 따옴표, 큰 따옴표 아무거나 써서 만들 수 있고, 작은 따옴표나 큰 따옴표를 양쪽에 세 개씩 쓰면 여러 줄에 걸쳐 만들 수 있다.

str은 꽤 복잡하게 구현돼있다. 이 블로그에 자세하게 설명돼있다

 

바이너리 시퀀스는 bytes, bytearray가 있고 memoryview에 의해 지원된다고 한다.

 

 

3. 매핑 (mappings)

매핑은 사전(dict=dictionary)으로 표현되기도 한다. Key-Value를 저장하는 형식이다. 가변 객체이다.

>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}

>>> type(a)
<class 'dict'>

>>> a == b
True

>>> a.get('one') == b['one']
True

dict 생성자를 사용해도 되고, object 형식을 사용해도 된다. 단 object 형식으로 쓸 때는 key를 문자열 형식으로 입력해야 한다. dict 키워드를 사용할 때는 kwargs로 입력했을 때 name=value pair로 만들어준다.

get 메소드나 [] 연산자로 접근할 수 있다

 

 

4. 예외 (exceptions)

try:
    with open('config.json', 'r', encoding='UTF8') as f:
        config = json.load(f)
except IOError:
    config = {}
finally:
    print("config 생성 완료")

파이썬에서 예외는 BaseException에서 파생된 클래스의 인스턴스들이며, try - except 구문으로 예외를 던지고 받을 수 있다. C의 try catch 생각하면 된다.

 

try_stmt  ::=  try1_stmt | try2_stmt
try1_stmt ::=  "try" ":" suite
               ("except" [expression ["as" identifier]] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
try2_stmt ::=  "try" ":" suite
               "finally" ":" suite

이걸 뭐라고 하더라? 분명 컴파일러 시간에 배운건데... 암튼 위 토큰 형식을 보면 어떻게 쓰는 지 대충 감이 올 것이다. try로 구문 감싸고, except에서 처리하고 else는 예외가 없었을 때 실행된다. finally는 예외 유무에 상관없이 실행된다.

 

예외는 raise로 명시적으로 생성할 수도 있다.

반응형