Python Built-in 가지고 놀기

Python 2007. 8. 30. 17:05

기본컨셉: __builtin__

 Python에서는 모든것이 object이다. 그리고 모두 object class를 상속받아 정의되어 있다.

object class의 instance인 object는 모두 __ (underscore 2개) 로 둘러쌓인 __bultins__ 를 물려받게 된다. __builtins__ 와 object는 모두 __builtin__에 정의되어 있다. 이 모듈은 파이썬이 시작되면서 항상 로드되는 파이썬의 가장 밑바닥의 초석이다. 파이썬이 실행되면 마치 from __builtin__ import *; import __builtin__ as __builtins__ 를 수행한것과 같은 상태라고 생각하면 쉽다.(꼭 같지는 않다. python 기본 실행 상태에서 __main__이라는 이름을 가지는 메인스레드에서 __builtin__의 모든 name을 디렉토리에 갖고 있지는 않다. dir()로 확인해보시길..)

 python_builtin.png

위 화면을 보면, python을 실행만 하고 아무것도 안한 상태에서 기본으로 로드된 hash()와 repr()의 id는 강제로 __builtins__를 import 한 후에도 바뀌지 않는 것을 볼 수 있는데, Python은 import명령을 사용해도 이미 적재된 동일한 개체를 다시 적재하지 않기 때문이다. (강제로 다시 적재하고 싶을 때에는 reload()를 써야 한다.)


Python에는 C++과 같은 Operator overloading이 없다. 혹자들이 말하는 "코드를 어지럽게 만들 뿐인" 군더더기 문법은 존재하지 않는 것이고 이런 필요성을 모두 객체(object)에 흡수하였다. class를 정의할 때 instance의 __함수를 재정의(override)해 줌으로써, operator overloading을 구현할 수 있다.

__함수가 Python __builtin__의 모든것은 아니다. C/C++과 같은 전통적인(?) 언어에서 built-in data types라고 말하는 int, float, 등등이 Python에서는 모두 object로 다루어지기 때문에 이런 유용한 기본 데이터타입 역시 __builtin__에서 정의하고 있다.


Built-in Data Types

  • 이 문서에는 전통적으로 built-in type으로 알려져있는 각종 상수들과 몇몇 자주 쓰이는 기본적인 데이터 타입만 다루고 있다. 자세한 내용은 pydoc __builtins__에서 확인할 수 있다.
  • Number
    • int(), long(): int()는 정수객체를 리턴하는 built-in 함수처럼 사용할 수 있지만, 사실은 int 라는 클래스의 생성자(__init__()함수) 를 호출하여 객체를 만드는 클래스의 이름이다.
      • 널리 쓰이는 32비트 프로세서에서 2**32-1이 int object가 가질 수 있는 최대값이다. 이 값보다 크면 int는 long object를 생성하여 리턴한다. long은 크기 제한이 없다.
      • int, long 모두 한개 또는 두 개의 인자를 받아 object를 생성한다. 필수 인자인 첫번째 인자는 10진수 정수값 또는 정수값이 될수 있는 문자열이며, 선택사항인 두번째 인자는 기수법이다. 단 두번째 인자를 가질 때에는 첫번째 인자는 정수가 될 수 없다.
    • float(): 소수점 이하의 값이 있는 실수형의 데이터
      • 정수의 경우와 마찬가지로 float class의 instance가 생성된다.
    • complex(): 실수부와 허수부를 갖는 복소수 데이터
  • String
    • __builtin__.object.basestring.str과 __builtin__.object.basestring.unicode 의 두가지 문자열이 있다.
    • str는 확장ASCII문자열까지 사용할 수 있다.
    • unicode는 생성자 두번째 인자로 넘겨주는 인코딩의 unicode문자열을 사용할 수 있다.
  • Collection
    • 순서가 있는 sequence과 순서가 없는 set이 있다. object생성후 값의 일부를 수정할 수 없는 immutable과 수정할수 있는 mutable이 있다.
    • Python의 Collection 타입들은 한가지 데이터타입의 원소만을 모을 필요가 없다. 정수, 실수, class instance등을 한곳에 묶어둘 수 있다. 이를테면, [1, 2.5, "asdf"] 는 정상적인 list object이다.
    • tuple(): immutable sequence. t = (1, 2, 3) 과 같이 괄호()로 묶은 n차원의 순서쌍. t[1] == 2이지만, t[1] = 3은 불가능하다.
      • 참고: str, unicode 도 tuple과 같이 일부를 수정할수 없는 immutable이다.
    • list(): mutable sequence. l = [1, 2, 3] 과 같이 괄호[]로 묶은 n개의 배열. C/C++/JAVA의 array와 같은 표기방식. l[1] = 5와 같이 일부를 수정할 수 있다.
    • set(): mutable set. s = set([1, 2, 3, 3, 4]) 와 같이 Iterable object를 unique원소의 집합으로 만든다. 이 경우 s는 1, 2, 3, 4의 4개의 원소를 갖는다. ss = set([5, 4, 3, 2, 1])라고 ss를 만들어도 ss는 1, 2, 3, 4, 5 5개의 순서를 유지하지 않는다.
      • 여러개의 set object에 대해 교집합(intersection), 합집합(union), 차집합(difference)의 연산을 할 수 있도록 set class에 정의되어 있다. 이 연산들은 class method이기 때문에, set.union(s, ss) 또는 s.union(ss) 의 두가지 사용법이 모두 가능하다.
    • dict(): mutable set. d = {"a":1, "b":2, "c":3}와 같이 괄호{}로 묶은 n개의 Key:Value 쌍. d[key] = value와 같이 []연산자안에 key를 주어 값에 접근 또는 수정, 추가를 할 수 있다. 즉, d["a"] == 1이고, d["b"] = 20으로 수정 가능하고, d["d"] = 4와 같이 추가 가능하다.

알아두면 유용한 _ _ 함수

  • 이곳에 나열한 것이 builtin의 전부는 아니다.
  • __repr__()이 정의되어 있는 class의 instance는 repr() 함수의 인자로 줄수 있다. 마찬가지로, __add__()가 정의되어 있는 class의 instance는 + 연산자의 좌측(L-value)로 사용할 수 있다.
    • repr()과 __repr__()은 다른 함수이다. 이문서에서의 repr(x) == x.__repr__()와 같은 표기는 이 절의 나머지 함수들에도 똑같이 적용되며 굳이 매번 설명을 달지는 않았다. 일반적으로 같은 결과가 리턴되는것 뿐이다. repr()함수는 __builtin__에 정의된 함수이며 object class의 함수이다. 이 함수는 내부적으로 인자로 받은 object의 __repr__()를 호출하여 받은 결과를 그대로 리턴한다. 이 역시 나머지 함수들의 설명에도 똑같이 적용되는 원리이다. 이를테면 int(x) == x.__int__()인 것은 int(x)가 x.__int__()를 호출한 결과를 리턴한다는 표현을 한 것이다. 하지만 int(x)는 바로 x.__int__()를 호출하여 이를 리턴하기만 하는 것은 아니므로 각 builtin에 대해서는 별도의 문서를 참고해야 한다. shell에서 pydoc __builtins__ 또는 python interactive mode에서 help(__builtins__)를 보면 된다.

표현, 타입캐스팅, 변환

  • __init__(): class의 constructor(생성자)
  • __repr__(): representation 함수
    • repr(x) == x.__repr__()
    • Python interactive mode의 프롬프트에서 아무 object나 하나 입력해 보자. 이때 엔터키 누른 직후에 나오는 것이 바로 그 object의 __repr__()값이다.
    • 많은 builtin data type은 그 내용이 분명하고 간단하기 때문에 __str__()과 같은 결과를 리턴한다. 즉, 문자열화한다. 이 경우에 __str__()과의 차이점은 object를 문자열로 표현하긴 하되, quoatation하지 않는다는 것이다. __repr__()을 명시적으로 부르면 quoatation한다.
    • 보다 복잡한 object (어떤 class로부터 생성한 instance)의 경우에는 <type과 object의 address>의 형태로 보여준다. 이는 __repr__()이 정의 되지 않았을 경우에 파이썬의 기본행동이다.

python_builtin_repr_.png


  • __str__(): 문자열 변환 함수
    • str(x) == x.__str__()
    • str변환이 일어나는 가장 대표적인 경우는 "%s" 로 문자열을 만들 때이다.
  • __int__():
    • int(x) == x.__int__()
    • 정수형으로 캐스팅을 시도한다.
    • 모든 class에 이 함수가 정의되어 있지는 않다. 상식적으로 정수로 캐스팅 될것 같지 않은 경우에는 (int로의 캐스팅이라는 기본행동이 정의되지 않는 클래스들) __int__()가 없기 때문에 int(x)를 시도하면 AttributeError라 발생한다.
  • __long__():
    • long(x) == x.__long__()
    • __int__()와 매우 유사.
  • __float__():
    • float(x) == x.__float__()
  • __hash__():
    • hash(x) == x.__hash__()
  • __getitem__(i):
    • list, tuple, basestring과 같은 순서가 있는 컬렉션 객체에 대해 특정 원소를 접근하는 방법을 제공한다.
    • []연산자 오버로딩에 해당한다. 즉, x[3] == x.__getitem__(3) 이다.
  • __getslice__(i, j):
    • __getitem__()과 같이 순서가 있는 컬렉션 객체에 대해 특정 구간의 원소를 접근하는 방법을 제공한다.
    • 특정구간의 원소집합을 slice라 한다.
    • x[3:5] == x.__getslice__(3,5) 는 3 <= index < 5를 만족하는 원소구간을 리턴한다.

산술연산자

  • 특정한 목적에 의해 설계된 class instance끼리의 사칙연산을 정의할 수 있다.
  • 연산자 오버로딩으로 생각하면 된다.
  • binary operators; __add__(), __sub__(), __mul__(), __div__(), __divmod__():
    • x + y == x.__add__(y)
    • x - y == x.__sub__(y)
    • x * y == x.__mul__(y)
    • x / y == x.__div__(y)
    • x % y == x.__divmod__(y)
  • unary operators; __neg__(), __pos__():
    • -x == x.__neg__()
    • +x == x.__pos__()

python_builtin_ex.png

이상의 내용을 사용하여 간단히 복소수 클래스를 정의한 경우

비교연산자

  • 산술 연산자보다 때로는 더욱 유용하고 막강한 기능이 비교연산자 함수를 오버로딩 하는 것이다. 이것들을 잘 정의해 두면, 비교구문을 단순화하여 보다 직관적이고 간단명료한 코드를 작성할 수 있다.
  • 비교연산구문과 마찬가지로 모두 bool값(True, False)를 리턴한다.
  • ==, >, >=, <, <=가 각각 __eq__(), __gt__(), __ge__(), __lt__(), __le__()이다.
    • x == y : x.__eq__(y) ; x is EQual to y
    • x > y : x.__gt__(y) ; x is Grater Than y
    • x >= y : x.__ge__(y) ; x is Grater than or Equal to y
    • x < y : x.__lt__(y) ; x is Less Than y
    • x <= y : x.__le__(y) ; x is Less than or Equal to y

Reference

  • Python Documentation in python interactive mode

이 글은 스프링노트에서 작성되었습니다.

: