main-logo

파이썬 기초 간단하게 살펴보기2

파이썬 기초

profile
NY
2026년 05월 05일 · 0 분 소요

들어가며

이전 글에서는 if와 while 반복문, 다양한 타입, 그리고 코드 블록 같은 기초적인 내용들을 살펴봤습니다. 그러다 보니 자연스럽게 "이 변수는 자바스크립트와 어떻게 다르게 사용하려나?", "에러가 나면 어디서부터 확인해야 하지?", "파이썬의 클래스와 객체는 자바스크립트와 차이가 있을까?" 같은 궁금증이 생기기 시작했습니다.

저는 마크업과 프론트엔드 작업을 하다 보니, 아무래도 새로운 문법을 배울 때 자바스크립트와 비교해서 보게 되는 것 같습니다. 익숙한 개념 같다가도 파이썬에서는 조금 다르게 작성하거나 동작하는 부분들이 있어서, 이번에는 그런 부분들을 중심으로 정리해보았습니다.

이번 글에서는 scope, 디버깅, 그리고 객체지향 프로그래밍에 대해 가볍게 살펴보려고 합니다. (참고로 저는 "100 Days of Code: The Complete Python Pro Bootcamp"라는 강의를 듣고 있습니다.)

 

1. scope

프로그래밍을 하다 보면 "이 변수는 어디서 쓸 수 있지?" 같은 순간이 자주 생기는데요. 이때 알아두면 좋은 개념이 바로 scope입니다. 쉽게 말하면 변수가 유효한 범위라고 생각하시면 됩니다.

지역 변수와 전역 변수

파이썬에는 지역 변수(local variable)전역 변수(global variable)가 있습니다. 프로그래밍을 하다 보면 자주 접하는 개념이기도 한데요. 실제로 코드에서 어떻게 다르게 동작하는지 보면 더 이해가 쉬울 것 같습니다.

 # global scope
 # 어디에서든 사용할 수 있습니다
 my_var = 1

 def my_function():
     # 이름은 같지만 이 변수는 local scope
     # 해당 함수 안에서만 유효합니다
     my_var = 2
     print(my_var)

 my_function()  # 2
 print(my_var)  # 1

위 코드를 보면 my_var라는 이름을 똑같이 썼는데도 결과가 다릅니다. 함수 안의 my_var는 지역 변수이기 때문에 함수 바깥의 my_var와는 별개로 동작합니다.

처음 보면 "이름이 같은데 왜 값이 다르지?" 싶을 수 있는데, scope가 다르기 때문이라고 이해하시면 됩니다.

블록 범위

자바스크립트와 비교해서 보면 조금 다르게 느껴지는 부분도 있습니다. 파이썬에서는 if, while, for 같은 블록(block) 자체가 새로운 scope를 만들지 않습니다.

이 말이 조금 낯설 수 있는데요. 예를 들어 if문 안에서 새로운 변수를 만들었다고 해서, 그 변수가 if문 안에서만 살아있는 것은 아닙니다. 그 변수는 가장 가까운 함수 scope에 속하게 되고, 감싸는 함수가 없다면 전역 scope를 가지게 됩니다.

# 감싸는 함수가 없으므로 a_var는 전역 변수입니다
 if 3 > 2:
     a_var = 10

 print(a_var)  # 10

아래 예시를 보면 조금 더 이해가 쉬울 것 같습니다.

count = 3
items = ["apple", "orange", "mango"]

def my_function():
    new_item = ""

    # if 블록은 새로운 scope를 만들지 않습니다
    # 그래서 if 안에서 값을 바꾼 new_item은
    # 같은 함수 안의 print()에서 그대로 사용할 수 있습니다
    if count < 2:
        new_item = items[0]

    print(new_item)

my_function()

이 코드에서 new_item은 if문 안에서만 사용하는 변수가 아니라, 함수 안에서 선언된 지역 변수입니다. 즉 if문은 단지 값을 바꾸는 역할만 할 뿐이고, 새로운 범위를 만들지는 않습니다.

참고로 지금 예시에서는 count = 3이기 때문에 count < 2 조건이 거짓이라 new_item은 빈 문자열 그대로 출력됩니다.

전역 변수 수정하기

파이썬은 전역 변수를 수정하는 방법도 자바스크립트와는 조금 다르게 느껴질 수 있습니다. 

count = 0

def count_function():
    global count
    count += 1
    print(f"change count num: {count}")

count_function()
print(f"global count num: {count}")

파이썬에서는 함수 안에서 전역 변수를 직접 수정하려면 global 키워드를 선언해야 합니다. 이렇게 하면 함수 안의 count가 새로운 지역 변수가 아니라, 바깥에 있는 전역 변수 count를 가리키게 됩니다.

이렇게 전역 변수를 직접 수정하는 방법도 있다는 점은 알아두면 좋을 것 같습니다. 다만 실제로 작업할 때는 전역 변수를 직접 바꾸는 방식은 되도록 줄이는 편이 좋습니다. 값이 어디서 바뀌었는지 추적하기 어려워질 수 있기 때문입니다.

return

전역 변수를 직접 수정하지 않고 작업할 수 있는 방법도 있습니다. 앞전에 살펴봤던 return을 사용하면 됩니다.

count = 0

def count_function(count):
    print(f"change count num: {count}")
    return count + 1

count = count_function(count)
print(f"global count num: {count}")

이 코드는 전역 변수 count를 함수에 인자로 전달하고, 함수에서 변경된 값을 return으로 돌려준 뒤 다시 count에 저장하는 방식입니다.

보통은 global을 사용해서 전역 변수를 직접 수정하는 것보다, 이렇게 필요한 값을 함수에 전달하고 결과를 return으로 받아오는 방식을 더 많이 사용하게 되는 것 같습니다.

위에서 설명했듯이 전역 변수를 직접 건드리면 값이 어디서 바뀌었는지 흐름을 따라가기 어려워질 수 있어서, return으로 값을 주고받는 방식이 조금 더 안전하고 명확하다고 생각하시면 될 것 같습니다.

전역 변수와 전역 상수

전역 변수와 전역 상수는 비슷해 보이지만 조금 다릅니다. 보통 변경 가능성이 있는 값은 변수, 변경 가능성이 거의 없는 값은 상수처럼 생각하시면 됩니다.

파이썬에는 자바스크립트의 const처럼 상수를 강제로 막아주는 문법은 없지만, 보통 대문자 이름으로 선언해서 이 값은 바꾸지 않는 값이라고 약속하는 식으로 사용합니다.

PI = 3.14159
MAX_COUNT = 10

이 부분은 다른 개발 코드와도 비슷하니 참고해두시면 좋을 것 같습니다.

 

2. 디버깅

코드를 작성하다 보면 "분명 맞는 것 같은데 왜 안 되지?" 싶은 순간이 꼭 옵니다. 특히 자바스크립트와 문법이 비슷해 보여서 그대로 썼는데 예상과 다르게 동작하면 더 헷갈리기도 하더라고요. 이럴 때 필요한 것이 디버깅(debugging)입니다.

쉽게 말하면, 코드가 왜 예상과 다르게 동작하는지 확인하고 원인을 찾는 과정이라고 보시면 됩니다. 디버깅은 파이썬 뿐만 아니라 모든 개발 작업에 필수죠.

try / except

파이썬에서는 try와 except를 사용해서 오류가 발생했을 때 어떻게 처리할지 정할 수 있습니다.

try:
    member = int(input("How many members are there? "))
except ValueError:
    print("You have typed in an invalid number. Please try again with a numerical response such as 15.")
    member = int(input("How many members are there? "))

if member > 18:
    print("Up to 15 members.")

여기서 ValueError를 왜 쓰는지 처음에는 조금 헷갈릴 수 있습니다. 저도 처음에는 "에러가 난다는 건 알겠는데, 왜 이름이 ValueError일까?" 싶었는데요. 터미널의 에러 코드를 보고 이해가 되더라고요.

예를 들어 아래처럼 코드를 작성하고,

member = int(input("How many members are there? "))

터미널에 숫자가 아니라 hello를 입력하면 이런 식의 에러 메시지가 나옵니다.

How many members are there? hello
Traceback (most recent call last):
  File "main.py", line 1, in <module>
    member = int(input("How many members are there? "))
ValueError: invalid literal for int() with base 10: 'hello'

맨 마지막 줄을 보면 ValueError라고 적혀 있는 것을 확인할 수 있습니다. 즉, int()가 문자열을 숫자로 바꾸는 과정에서 문제가 생겼고, 파이썬이 그 에러의 이름을 ValueError라고 알려주는 것입니다.

그래서 try / except를 사용할 때도 위 예시 코드처럼 그 에러 이름을 그대로 적어주는 것입니다.

이렇게 보면 except ValueError:는 그냥 외워서 쓰는 문법이라기보다, 터미널에 표시된 에러 이름을 기준으로 처리하는 방식이라고 이해할 수 있습니다. 당연히 작업을 진행하면서 다른 에러가 나온다면 그 에러 이름을 반영해줘야 하겠죠.

print()로 확인하기

그 외 가장 손쉽게 사용할 수 있는 방법으로는 역시 print()가 있습니다. 자바스크립트에서 console.log()를 사용하는 것과 비슷하다고 생각하시면 됩니다. 각 코드 상황에 따라 문제가 될 것 같은 부분에 print()를 사용해서 값이 제대로 넘어오는지 확인해보면, 의외로 빨리 원인을 찾을 수 있습니다. 이 부분은 너무 익숙하실 것 같네요.

디버거 활용하기

직접 print()를 찍어보는 것 외에도 디버거 사이트나 도구들을 활용할 수 있습니다. 이 부분도 강의에서 함께 소개해주신 내용입니다.

예를 들어 pythontutor.com 같은 사이트에서는 코드가 한 줄씩 어떻게 실행되는지 시각적으로 볼 수 있고, Thonny 편집기에서도 디버거 기능을 사용할 수 있습니다.

처음에는 print()가 더 익숙할 수 있지만, 코드를 따라가며 확인해야 할 때는 이런 도구들도 꽤 도움이 될 것 같습니다.

 

3. 객체지향 프로그래밍

이제 객체지향 프로그래밍(Object-Oriented Programming, OOP)에 대해 알아보려고 합니다.

이 부분도 자바스크립트에서 비슷한 표현을 본 적은 있는데, 파이썬에서는 또 조금 다른 느낌이 있었습니다. 클래스, 객체, 속성, 메소드 같은 용어가 한꺼번에 나오다 보니 처음엔 조금 낯설게 느껴졌습니다.

클래스와 객체

보통 클래스는 객체를 생성하기 위한 블루프린트(blueprint)라고 설명합니다. 저도 강의에서 이 표현을 처음 들었는데, 개발 쪽에서 사용하는 용어인 것 같더라고요. 처음에는 조금 생소해서 찾아봤는데, 너무 어렵
게 생각하지 않아도 되고 그냥 객체를 만들기 위한 틀 정도로 이해하면 될 것 같았습니다.

저는 마크업과 프론트엔드 작업을 하다 보니 이걸 HTML 구조처럼 생각해보게 되었는데요. 예를 들어 같은 형태의 카드 UI를 여러 개 만든다고 하면, 제목과 설명, 버튼 위치 같은 기본 구조를 먼저 정해두는 경우가 있
잖아요. 클래스도 비슷하게 "이 객체는 어떤 값을 가지고, 어떤 기능을 할지"를 미리 정해두는 역할을 합니다.

즉, 클래스는 같은 방식의 객체를 여러 개 만들기 위한 기본 구조이고, 객체는 그 구조를 바탕으로 실제로 만들어진 각각의 결과물이라고 보면 될 것 같습니다.

속성과 메소드

객체를 만들면 속성(attribute)메소드(method)에 접근할 수 있습니다.

여기서 속성은 기본적으로 객체가 가지고 있는 값(변수)이라고 생각하시면 되고, 메소드는 그 객체가 할 수 있는 기능(함수)이라고 보면 됩니다.

예를 들어 자동차를 생각해보면,

  • 색상, 속도 같은 것은 속성
  • 출발하기, 멈추기 같은 것은 메소드

처럼 볼 수 있습니다.

조금 더 쉽게 말하면, 클래스는 객체의 기본 형태를 정해두는 것이고 속성과 메소드는 그 안에 들어가는 값과 기능이라고 이해하시면 될 것 같습니다.

클래스 만들기

파이썬에서 클래스는 보통 파스칼 표기법(PascalCase)으로 작성합니다.

class Car:
    pass

예를 들어 car_name처럼 전부 소문자로 쓰는 대신 Car, UserProfile처럼 각 단어의 첫 글자를 대문자로 쓰는 방식입니다.

생성자 init()

클래스에서 객체가 처음 만들어질 때 실행되는 특별한 함수가 있는데, 그것이 바로 init()입니다.

처음에는 이름이 조금 낯설 수 있는데요. init()는 객체가 생성될 때 속성의 초기값을 넣어주는 생성자(constructor) 역할을 합니다.

class User:
    def __init__(self, name):
        self.name = name

위 코드는 User 객체가 만들어질 때 name이라는 값을 받아서 self.name에 저장합니다.

메소드 추가하기

클래스 안에는 함수도 넣을 수 있는데, 이 함수를 메소드라고 부릅니다.
class User:
    def __init__(self, name):
        self.name = name

    def say_hello(self):
        print(f"안녕하세요, 저는 {self.name}입니다.")

user1 = User("혜름")
user1.say_hello()

이렇게 하면 user1이라는 객체는 자신의 이름을 가지고 인사하는 기능까지 함께 가지게 됩니다.

처음에는 함수와 메소드가 비슷해 보여도, 메소드는 특정 객체에 속한 함수라는 점이 차이입니다.

속성 변경과 메소드 호출

객체를 만든 뒤에는 속성 값을 바꿀 수도 있고, 메소드를 호출해서 기능을 실행할 수도 있습니다.

class Geoniq:
    def __init__(self, keyword, status):
        self.keyword = keyword
        self.status = status

    def check_seo(self):
        print(f"{self.keyword} 키워드의 SEO/GEO 검증을 시작합니다.")

geoniq = Geoniq("pxd", "ready")
geoniq.status = "running"

print(geoniq.status)  # running
geoniq.check_seo()

위 코드를 보면 geoniq라는 객체는 keyword, status라는 속성을 가지고 있고, check_seo()라는 메소드도 사용할 수 있습니다.

이렇게 객체를 만든 뒤에 status 값을 바꾸면 속성 변경이 되고, check_seo()를 실행하면 해당 객체의 기능을 호출하는 방식이 됩니다.

이런 식으로 관련 있는 값과 기능을 하나로 묶어서 다루는 것이 객체지향 프로그래밍의 기본적인 느낌이라고 보시면 될 것 같습니다.

 

4. 패키지와 PyPI

강의를 듣다 보니, 다른 개발자들이 어떤 목표를 달성하기 위해 만들어둔 패키지들을 검색할 수 있는 사이트도 알게 되었습니다. 대표적인 사이트가 바로 PyPI 입니다.

PyPI

이곳은 파이썬 커뮤니티에서 개발하고 공유하는 파이썬 프로그래밍 언어용 소프트웨어 모음입니다. 그래서 우리는 이곳에서 다양한 패키지를 찾아볼 수 있고, 경우에 따라서는 그들의 소스 코드도 참고할 수 있습니다.

무엇보다 중요한 것은, 이미 만들어진 기능을 어떻게 구현했고 또 우리의 프로젝트에 어떻게 넣을 수 있는지 확인할 수 있다는 점입니다. 공부를 하다 보면 "이런 것도 직접 다 만들어야 하나?" 싶은 순간이 있는데, 그럴 때 PyPI를 보면 정말 다양한 자료가 있다는 걸 알 수 있습니다.

 

마치며

이번 글에서는 scope, 디버깅, 객체지향 프로그래밍, 그리고 PyPI에 대해 간단하게 살펴봤습니다. 처음에는 익숙한 개념 같다가도 파이썬에서는 조금 다르게 느껴지는 부분들이 있었는데, 하나씩 예시 코드를 보다 보니 왜 이런 방식으로 쓰는지 조금씩 이해가 되는 것 같았습니다.

특히 변수의 범위, 에러를 처리하는 방식, 클래스와 객체의 개념은 앞으로도 계속 보게 될 내용이라 미리 익숙해져두면 좋을 것 같습니다. 공부를 계속하면서 새로 알게 되는 내용이 있으면 이어서 정리해보겠습니다.

부족한 글 읽어주셔서 감사합니다.🙇🏻‍♀
그럼 안녕히…👋

 

참고 자료