1  R 언어에 익숙한 사용자가 Python을 배울 때 생소하게 느끼는 특징들

R 언어와 Python 언어는 모두 인터프리트 언어(interpreted lanugage)이고 대화식 프로그래밍 언어(interactive programming language)이다. 따라서 코드를 작성하고 실행하는 방법이 비슷하다.

그렇지만 실제로 파이썬을 배우기 시작하면 뭔가 다른 점들이 많다는 것을 알게 된다. 이 장에서는 R 언어에 익숙한 사람들이 Python 언어를 배울 때 생소하고 어려운 점들과 개인 경험에 비추어 중요하다고 판단되는 것들을정리하려고 한다.

1.1 파이썬을 다루려면 명령행 인터페이스(command line interface)에 어느 정도 익숙해질 필요가 있다.

명령행 인터페이스는 이전 윈도우 시스템의 명령 프롬프트(command prompt), 최근 윈도우 시스템의 윈도우 터미널(Windows Terminal), 맥오에스에서는 터미널(Temrinal) 앱을 통해 사용되는 텍스트 기반 사용자 인터페이스를 말한다.

그림 1.1: 윈도우 터미널

예를 들어, R 패키지를 새로 설치할 때 R 세션을 종료할 필요 없이 install.packages("tidyverse")와 같은 함수를 실행하거나 RStudio의 버튼을 클릭하면 되었었다. 그런데 파이썬에는 pip, conda 그리고 최근 나온 uv까지 명령행 인터페이스에서 실행해야 하는 도구들을 사용하여 인스톨하는 경우가 많다. 이밖에도 더 많이 있다. 명령행 인터페이스도 익숙하지 않은데, 도구도 여러 가지라 선택하기 쉽지 않다.

모양이 이렇다고 지레 겁을 필요는 없다. 명령행 인터페이스의 세계도 넓지만 실용적이 관점에서 필요한 만큼 배워 필요한 만큼 사용한다고 마음 먹으면 좋겠다. 파이썬을 사용하는 데 무리 없도록 기초는 설명할 예정이다. 명령행 인터페이스에 대한 기초는 뒤에서 설명한다.

1.2 파이썬에서는 가상환경(virtual environment)을 자주 사용한다.

보통 비전문가들에게 어떤 앱을 설치하고 사용한다고 했을 때, 머릿속에 그려지는 인상은 뭔가 “하나”를 설치하고, 그 프로그램을 실행하여 파일을 만들고 그것을 어떤 디렉터리에 저장하는 것이다. R 언어 실행 환경을 구축하는 방법도 대체로 이와 비슷한다. R 언어 설치 파일을 하나 다운로드하여 이것을 설치하여 여러 곳에서 사용하는 것이 보통이다(물론, 다음 설명하는 방법이 없는 것은 아니다).

Python 언어는 설치하는 방법도 다양하고 (책/블로그 등에서 소개하는) 실행 환경을 구축하는 방법도 다양한다. 이런 다양성이 Python 언어의 특징이기도 하다. 그러나 처음 배우는 사람들에게는 선택의 어려움을 준다. Python 실행 환경은 가상환경(virtual environment)을 구성하고, 이를 활성화한 다음 사용하는 것이 보통이다. 그런데, 이런 가상환경을 만드는 도구도 많다. 어느 것이 좋은 방법인지…? 언제는 그 답은 “It depends on …”이다.

가상환경은 독립된 파이썬 버전과 거기에 따른 패키지 등으로 구성된다. 이런 가상환경에 하나의 컴퓨터 안에 여러 개가 존재할 수 있고, 심지어 프로젝트 폴더당 하나씩 만들어 사용하기도 한다.

일단 그렇게 하는 이유는 Python 언어는 범용 언어(general purpose language)여서 다양한 용도로 쓰이며, 또 다양한 파이썬 패키지가 개발되어 있고, 이들 패키지들의 의존성이 복잡하기 때문에 이를 체계적으로 관리해야 할 필요가 있기 때문이다.

뒤에서 좀 더 구체적으로 설명할 예정이다.

1.3 파이썬은 객체 지향형 언어(Object-Oriented Programming, OOP)이다.

프로그래밍 언어를 정식으로 배우지 않았거나 주로 R 언어와 같이 덜 엄격한 프로그래밍 언어만 배운 경우 Python 언어를 처음 배울 때 어려워하는 개념이 객체 지향형 프로그래밍이다.

객체 지향형 프로그래밍은 클래스(class)객체(object)를 기반으로 프로그래밍하는 방법이다. 클래스는 객체를 정의하고, 객체는 클래스의 인스턴스(instance)이다. 파이썬을 배우는 것이나 사용하는 것은 이런객체 지향형 프로그래밍 방식에 따르기 때문에, 시간을 들여서라도 반드시 알아야 하는 개념이다.

R 언어에도 S3, S4, R6 등의 클래스 시스템이 있지만 암묵적으로 사용되고 명시적으로 사용자가 이것들을 염두해 둬야 하는 경우는 많지 않다. 그러나 파이썬에서는 거의 항상 클래스를 소개하고, 해당 클래스로 객체를 생성하고, 그 객체(인스턴스)가 가지고 있는 메서드는 이렇게 사용한다고 말한다.

클래스 정의에서 시작하고 객체를 만들고 사용하는 예시를 잠깜 보자. 수학에서 벡터를 객체 지향형 프로그래밍 방식으로 표현하면 다음과 같다.

import math
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def length(self):
        return math.sqrt(self.x**2 + self.y**2)
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

Vector 클래스를 정의했고, 이 클래스는 벡터의 길이를 계산하는 함수(메서드, method)와 벡터의 덧셈을 계산하는 함수를 가지고 있다. 사용할 때는 다음과 같이 한다.

v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2
v3
Vector(4, 6)
v3.length()
7.211102550927978

1.4 파이썬에는 Mutable과 Immutable 객체가 있다.

R 언어는 거의 모든 데이터 타입이 immutable하다. 이것은 R 언어가 객체 지향형 보다는 함수형 언어(functional programming language)에 가깝기 때문이다.

파이썬에서는 immutable 데이터 타입과 mutable 데이터 타입이 존재하기 때문에 명확히 이해하고 사용해야 한다.

  • immutable 데이터 타입: 숫자, 문자열, 튜플, 불리언
  • mutable 데이터 타입: 리스트, 딕셔너리, 세트

1.5 파이썬의 인덱스는 0부터 시작한다. 범위는 처음은 inclusive하고, 마지막은 exclusive하다.

파이썬의 인덱스는 0부터 시작한다. 예를 들어 다음과 같은 리스트가 있다고 하자.

a = [1, 2, 3, 4, 5]

이 리스트의 첫 번째 요소는 a[0]이고, 마지막 요소는 a[-1]이다.

a[0]
a[-1]
5

범위는 슬라이스(slice)라고 부르는데, 대부분 처음은 inclusive하고, 마지막은 exclusive하다. 예를 들어 다음과 같은 리스트가 있다고 하자.

b = [1, 2, 3, 4, 5]

2번째에서 4번째 요소까지 가져오려면 다음과 같이 한다.

b[2:4]
[3, 4]

1.6 파이썬은 파이써닉(pythonic) 코드를 지향한다.

Python을 배우다 보면 pythonic이라는 단어를 자주 접하게 된다. 이 단어는 파이썬 프로그래밍 언어의 특징을 설명하는 단어로, 파이썬 프로그래밍 언어의 특징을 잘 반영하는 코드를 의미한다. 처음 Python을 배울 때는 이 말의 의미를 바로 파악하기는 쉽지 않다. 그러나 경험이 쌓이면서 점점 더 이 말의 의미를 파악하게 될 것이다.

예를 들어 0에서 9까지 값을 가진 리스트에 있는 요소들을 각각 제곱하려면, 다음과 같이 리스트 컴프피헨션(list comprehension)을 사용할 수 있다. 이것은 pythonic한 측면이 있다.

# pythonic
squares = [x**2 for x in range(10)]
squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

이 코드는 다음과 같은 의미를 가지는데, 이것은 less pythonic한 측면이 있다.

# less pythonic
squares = []
for x in range(10):
    squares.append(x**2)
squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

1.7 Pythonic 코드의 비밀은 Python Data Model에 있다.

위 코드에서 Vector는 클래스이고, v1, v2, v3는 클래스의 인스턴스라고 한다. 클래스에는 이 클래스에서 속하는 인스턴스에 대하여 적용할 수 있는 메서드가 정의되어 있다. 메서드는 객체에 속하는 함수(function)이며, 이런 메서드는 . 연산자를 사용하여 호출한다.

클래스는 class 키워드로, 함수(메서드)는 def 키워드로 정의한다. 메서드 가운데는 두 개의 언더스코어를 앞과 뒤에 가지는 이름의 메서드가 있는데, 이런 것을 특별 메서드(special method)라고 한다. 어떤 책에는 “double underscore”여서 “dunder”라는 이름으로 부르거나 마법같다고해서 “magic method”라고 부르기도 한다. 이런 특별 메서드는 파이썬 언어에서 정의된 특별한 의미를 가지고 있다. 예를 들어 __add__가 정의됨으로써 완전히 새로운 벡터라는 객체들끼리 덧셈 연산자 +를 사용할 수 있게 된다.

이런 개념은 Python Data Model과 연관되어 있다.

  • 객체의 행동(behavior)을 어떻게 정의하고 확장할 것인가?
  • 내장 함수 (len, str, iter, add 등)에 어떻게 대응시킬 것인가?
  • 사용자 정의 객체를 내장된 데이터터 타입처럼 동작하게 하려면 어떻게 해야 하나?

1.8 기죽지 말자!

여기 나열한 것들 이외에도 다른 점은 많다. 이건 공시적인 것이 아니고 R 언어와 Python 언어를 공부했던 개인 경험에서 몇 자 적어본 것이다. 파이썬을 어느 정도 배우면 정말 아름답고 쉽고 강력하고 재미있고 읽기에도 편한 언어라는 것을 알게 될 것이다.