Lina's Toolbox

Python 심화 강의 / 변수 유효 범위(variable scope), 전역변수, 지역변수, global 키워드, try exception 예외처리, 패킹, 언패킹, 상속 본문

스파르타 내일 배움 캠프 AI 웹개발 과정/python

Python 심화 강의 / 변수 유효 범위(variable scope), 전역변수, 지역변수, global 키워드, try exception 예외처리, 패킹, 언패킹, 상속

Woolina 2024. 7. 8. 16:55

 

 


변수 유효 범위(variable scope)

python을 포함한 대부분의 언어에는 "변수 유효 범위"라는 개념이 있습니다.

변수가 선언된 위치나 키워드에 따라 변수를 사용할 수 있는 범위가 달라지게 되는데,
이를 변수 유효 범위 혹은 variable scope라고 부릅니다.

파이썬에서 변수는 유효 범위에 따라 지역 변수(local variable)전역 변수(global variable)로 나뉘게 됩니다.

지역 변수는 함수 내부에서 선언되며 다른  함수에 영향을 끼치지 않습니다.
반대로 전역 변수는 함수 밖에서 선언되며 어디서든 접근할 수 있습니다.

지역 변수로 선언된 변수는 global 키워드를 사용해 전역 변수로 재선언할 수 있습니다.

 

 

지역 변수(local variable)

def func1():
    number = 10 # 함수 내에서 number라는 지역 변수를 선언
    
def func2():
    print(number) # func1에서 생성된 지역 변수는 funt2에서 접근할 수 없다. -> 에러발생!!
    
func1()
func2()

"""
Traceback (most recent call last):
  File "sample.py", line 8, in <module>
    func2()
  File "sample.py", line 5, in function2
    print(number)
NameError: name 'number' is not defined
"""

 

 

전역 변수(global variable)

number = 10 # 함수 밖에서 number라는 전역 변수 생성

def func():
    print(number) # 전역 변수는 자유롭게 접근할 수 있다.
    
func() # 함수를 실행하면 10이 정상적으로 출력된다.

 

 

 

그렇다면 무조건 전역 변수가 더 좋은 것인가? 🙅🏻‍♀️

 

전역 변수 사용 시 주의할 점

 

📌  함수 내에서 전역 변수의 값을 바꾸려 할 경우

number = 10

def func():
    number = 5 # 전역 변수의 값이 바뀌는 것이 아닌, 지역 변수로 다시 선언됩니다.
    
func()

# 함수 내에서 재할당 된 지역 변수는 전역 변수에 영향을 끼치지 않습니다.
print(number) # 10

 

 

📌  전역 변수 사용과 지역 변수 할당을 같이 하는 경우

number = 10

# 전역 변수인 10을 출력하고 지역 변수로 다시 선언하는 코드 작성
def func():
    print(number)
    number = 5

# 실행시켜 보면 에러가 발생한다.
func()
"""
Traceback (most recent call last):
  File "sample.py", line 7, in <module>
    func()
  File "sample.py", line 4, in func
    print(number)
UnboundLocalError: local variable 'number' referenced before assignment
"""

➡️ 왜 에러가 발생할까?

함수 내부에서 전역 변수와 동일한 이름으로 지역 변수를 할당할 경우 함수에서는
해당 변수를 지역 변수로 간주하게 됩니다. 때문에 print(number)에서는 number라는
지역 변수가 선언되기 전 출력하려 했기 때문에 이와 같은 에러가 발생합니다.

 

number = 10

# 전역 변수인 10을 출력하고 지역 변수로 다시 선언하는 코드 작성
def func():
 	number = 5
    print(number)
   
func() # 5

이렇게 두 라인 위치를 바꿔서 실행할 경우, 에러가 나지 않고,
5가 출력된다.

 

 

📌  함수 내에서 전역 변수의 값을 바꾸려면?

global 키워드를 사용해 함수 내에서 전역 변수를 자유롭게 다시 할당할 수 있다.

number = 10

def func():
    global number # 함수에서 number 변수를 다시 할당할 수 있도록 해줍니다.
    number = 5 # global 키워드를 사용했기 때문에 전역 변수의 값이 변경됩니다.
    
func()

print(number) # 5

 

 

📌  전역 변수를 권장하지 않는 이유

파이썬을 포함한 많은 프로그래밍 언어에서 전역 변수를 남용하는 것은 권장하지 않습니다.

코드가 길어질수록 전역 변수로 선언 된 값은 어디서 값이 변했는지 추적하기 어렵고,
문제가 생겼을 때 디버깅을 하기 어려워 지기 때문입니다.

이와 같은 이유로 PIE = 3.14와 같은 전역 상수를 선언하는 것을 제외하면 전역 변수를
사용하지 않는 것이 좋은 코드를 만드는 방법입니다.

 

https://stackoverflow.com/questions/19158339/why-are-global-variables-evil

 

Why are global variables evil?

I'm trying to find out why the use of global is considered to be bad practice in python (and in programming in general). Can somebody explain? Links with more info would also be appreciated.

stackoverflow.com

 

다른 함수에서 사용된 결과갑을 사용하고 싶다면, 

변수에 저장하여 사용하는 것이 아니라

함수에서 return 값으로 보내주는 것을 사용하는 형태가 좋다.

 


자주 사용되는 모듈 및 패턴

 

integer = 10
float_ = 1.23
string = "hello world!!"
list_ = [1, 2, 3]
tuple_ = (1, 2, 3)
set_ = {1, 2, 3}
dictionary = {"key": "value"}
boolean = True

print(type(integer)) # <class 'int'>
print(type(float_)) # <class 'float'>
print(type(string)) # <class 'str'>
print(type(list_)) # <class 'list'>
print(type(tuple_)) # <class 'tuple'>
print(type(set_)) # <class 'set'>
print(type(dictionary)) # <class 'dict'>
print(type(boolean)) # <class 'bool'>

 

 

  • join() / list를 string으로 변환하기
# join은 "사이에 들어갈 문자".join(리스트) 로 구성되어 있습니다.

string_list = ["hello", "python", "world"]
string = "!! ".join(string_list)

print(string) # hello!! python!! world

 

 

  • replace() / 문자열 바꾸기
# replace는 "변경할 문자".replace("변경 전 문자", "변경 후 문자")로 구성되어 있습니다.

before_string = "hello world!!!"
after_string = before_string.replace("!", "~") # !를 ~로 변경

print(after_string) # hello world~~~

 

 

  • pprint() / 코드 예쁘게 출력하기
# pprint는 pretty print의 약자이며, 데이터를 더 예쁘게 출력해 줍니다.
from pprint import pprint

sample_data = {
    "id": "0001",
    "type": "donut",
    "name": "Cake",
    "ppu": 0.55,
    "batters":
        {
            "batter":
                [
                    {"id": "1001", "type": "Regular"},
                    {"id": "1002", "type": "Chocolate"},
                    {"id": "1003", "type": "Blueberry"},
                    {"id": "1004", "type": "Devil's Food"}
                ]
        },
    "topping":
        [
            {"id": "5001", "type": "None"},
            {"id": "5002", "type": "Glazed"},
            {"id": "5005", "type": "Sugar"},
            {"id": "5007", "type": "Powdered Sugar"},
            {"id": "5006", "type": "Chocolate with Sprinkles"},
            {"id": "5003", "type": "Chocolate"},
            {"id": "5004", "type": "Maple"}
        ]
}

pprint(sample_data) # print로 출력했을 때와 결과 비교해 보기!!

 

 

  • random / 랜덤한 로직이 필요할 때
# 난수 생성, 임의의 번호 생성 등 랜덤한 동작이 필요할 때 사용
import random

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
random.shuffle(numbers) # numbers를 무작위하게 섞기
print(numbers) # [2, 8, 6, 4, 3, 7, 1, 5]

random_number = random.randint(1, 10) # 1 ~ 10 사이의 무작위 번호 생성
print(random_number) # 4

 

 

  • time / 시간 다루기
import time

start_time = time.time() # 현재 시간 저장

time.sleep(1) # 1초간 대기

end_time = time.time()

# 코드가 종료된 시간 - 코드가 시작된 시간으로 실행 시간 구하기 (단위 : 초)
print(f"코드 실행 시간 : {end_time-start_time:.5f}") # 코드 실행 시간 : 1.00100

time.sleep(n) -> n초 동안 실행 시간이 늘어난다. (해당 위치에서 대기)

 

 

  • datetime / 날짜 다루기
from datetime import datetime, timedelta

# 현재 날짜 및 시간 출력
print(datetime.now()) # 2023-02-22 15:55:32.277095

# datetime의 format code 더 제세한건 여기서 확인 가능합니다.
'''
%y : 두 자리 연도 / 20, 21, 22
%Y : 네 자리 연도 / 2020, 2021, 2022
%m : 두 자리 월 / 01, 02 ... 11 ,12
%d : 두 자리 일 / 01, 02 ...  30, 31
%I : 12시간제 시간 / 01, 02 ... 12
%H : 24시간제의 시간 / 00, 01 ... 23
%M : 두 자리 분 / 00, 01 ... 58, 59
%S : 두 자리 초 / 00, 01 ... 58, 59
'''

# string을 datetime 날짜로 변경하기
string_datetime = "23/12/25 13:20"
datetime_ = datetime.strptime(string_datetime, "%y/%m/%d %H:%M")
print(datetime_) # 2023-12-25 13:20:00

# datetime 날짜를 string으로 변환하기
now = datetime.now()
string_datetime = datetime.strftime(now, "%y/%m/%d %H:%M:%S")
print(string_datetime) # 22/09/04 04:04

# 3일 전 날짜 구하기
three_days_ago = datetime.now() - timedelta(days=3)
print(three_days_ago) # 2023-02-19 16:27:52.526502

timedelta : 시간을 더하고 뺄 때 사용한다.

 

 

datetime 에서 날짜, 시간을 분리하고 싶을 경우

from datetime import datetime

now = datetime.now()

# datetime은 str이 아니므로 형변환 해주어야함. (안하면 에러!!)
now = str(now)

now = now.split()

print(now)

 


조건문 심화

 

'''== : 값이 일치하는지 비교'''
"a" == "a" # True
"a" == "b" # False
1 == "1" # False, 값은 동일하지만 자료형이 다르기 때문

'''!= : 값이 일치하지 않는지 비교'''
0 != 1 # True
0 != 0 # False

'''>, < : 값이 큰지 작은지 비교'''
5 > 2 # True
1 < 0 # False
1 > 1 # False

'''>=, <= : 값이 크거나 같은지, 작거나 같은지 비교'''
1 >= 1 # True

'''in : 특정 값이 list / tuple / set에 포함되어 있는지 확인'''
4 in [1, 2, 3] # False
1 in (1, 2, 3) # True

# 모든 비교 연산자의 결과는 print()로 확인할 수 있습니다.
print(1 == 1) # True
if True:
	pass
    
if False:
	pass
    
# 이런 형태로도 사용 가능

 

# 2개 이상의 조건을 복합적으로 사용할 때

if condition1 and condition2: # 두 조건을 모두 만족할 경우
    # some code

elif condition or condition: # 두 조건 중 하나라도 만족할 경우
    # some code

else: 
    # some code

3개 이상일 경우는 괄호() 사용하여 우선순위 부여할 것.

 

 

 

비어있는 string, list 등은 분기문에서 False로 판단한다. (내용이 있으면 무조건  True)

🚨 단, [""]는 True임!! 리스트에 "empty string"이라는 요소가 있는 것이므로.

print(bool(""))
print(bool(0))
print(bool([]))


print(bool("sample"))
print(bool([1, 2]))
print(bool(1))
print(bool(-1)) # 0이 아닌 숫자는 True로 판단

print(bool([""])) # 빈 스트링이라는 요소가 있으므로 True

# sample result
"""
False
False
False

True
True
True
True

True
"""

 

 

# all() : 요소들이 모두 True일 경우 True 리턴

if all([True, True, True, False, True]):
    print("통과!") # False가 존재하기 때문에 분기문을 통과하지 못함


# any() : 요소들 중 하나라도 True일 경우 True 리턴

if any([False, False, False, True, False]):
    print("통과!") # True가 1개 이상 존재하기 때문에 분기문을 통과함

 


 

함수의 인자와 리턴 타입

 

python에서 사용되는 함수들은 비슷해 보여도 사용 방법이나 리턴 타입들이 다를 수 있다.

그렇기 때문에 특정 기능을 사용할 때 해당 기능의 결과물이 어떤 데이터를 리턴해 주는지 알아야 한다.

 

list를 정렬하기 위해서는 sorted 혹은 list.sort()를 사용하지만 두 함수는 사용하는 방법이 다르다.

# sort
sample_list = [3, 2, 4, 1, 5]
sample_list.sort() # return data 없이 list 자체를 정렬

print(sample_list) # [1, 2, 3, 4, 5]

# sorted
sample_list = [3, 2, 4, 1, 5]
sorted_list = sorted(sample_list) # 정렬 된 list를 return

print(sorted_list) # [1, 2, 3, 4, 5]

# 잘못된 방법
sample_list = [3, 2, 4, 1, 5]
sorted_list = sample_list.sort() # .sort()의 return data는 None 입니다.

print(sorted_list) # None

 

 

 

 

내가 사용하는 코드의 리턴 타입을 확인하는 방법

 

함수를 사용하기 위해서는 이 함수를 통해 어떤 결과를 얻을 수 있는지 알아야 한다.

 

1. 검색
google에 python 함수명과 같은 형태로 검색해서 해당 기능을 어떻게 사용해야 하는지 확인합니다.
단순하게 검색하려는 함수를 어떻게 사용하는지에 대한 내용은 한글로 검색해도 되지만 더 많은 정보를 얻고 싶다면 영어로 검색하시는 것을 권장드립니다.

 


2. docstring 확인
함수를 작성할 때 docstring을 활용하면 사용하려는 함수가 어떤 역할을 하는지, 어떤 값을 인자로 받는지, 어떤 값을 리턴해주는지 확인할 수 있습니다.

 

 

 

3. 함수 구현 코드 확인 (가장 추천하는 방법!)
내장함수의 경우 c언어로 컴파일 되어 있는 경우가 많아 때문에 해당하지 않을 수 있지만, 특히 외부 라이브러리를 import 해서 사용할 때는 구현부의 코드를 보고 사용 방법을 익히는 것도 좋은 방법입니다. 

이해가 잘 되지 않더라도 잘하는 사람이 작성한 어려운 코드를 읽는 습관을 들이는 게 좋다!

 

💡 vscode에서 사용하는 함수를 ctrl + click 하면 구현 코드를 확인할 수 있다.


 

try/ exception을 활용한 에러 처리

 

number = "num"

try: # try 구문 안에서 에러가 발생할 경우 except로 넘어감
    number = int(number) # "num"을 숫자로 바꾸는 과정에서 에러 발생
    
except: # 에러가 발생했을 때 처리
    print(f"{number}은(는) 숫자가 아닙니다.")

 

에러 종류에 따라 다른 로직 처리도 가능하다!

number = input()

try:
    int(number)
    10 / number

except ValueError: # int로 변환하는 과정에서 에러가 발생했을 떄
    print(f"{number}은(는) 숫자가 아닙니다.")
    
except ZeroDivisionError: # 0으로 나누면서 에러가 발생했을 때
    print("0으로는 나눌수 없습니다.")

    # Exception에 대한 내용을 e라는 변수에 할당
except Exception as e: # 위에서 정의하지 않은 에러가 발생했을 때(권장하지 않음)
    print(f"예상하지 못한 에러가 발생했습니다. error : {e}")


# except 문법 또한 if / elif와 같이 연달아서 작성할 수 있다.

except: 이나 except Exception as e: 같은 정의하지 않은 모든 에러에 대한 예외 처리는 추천하지 않음.

특정에러(ex. ValueError) 별로 작성해주는게 좋다. 안그러면 왜 이 에러가 발생했는 지 추적이 어려워질 수 있다.


 

패킹과 언패킹

 

패킹(packing)언패킹(unpacking)은 단어의 뜻 그대로 요소들을 묶어주거나 풀어주는 것을 의미한다.
list 혹은 dictionary의 값을 함수에 입력할 때 주로 사용된다.

 

 

  • list 에서의 활용
def add(*args):
    result = 0
    for i in args:
        result += i
        
    return result

numbers = [1, 2, 3, 4]

# 함수에 인자 넣을 때에도 * 붙여서 사용
print(add(*numbers))


""" 아래 코드와 동일
print(add(1, 2, 3, 4))
"""

# result output
"""
10
"""

*args는 위치 인자 목록을 받는다. 다른 이름 써도 상관 없지만 통상적으로 arguments의 *args를 사용

numbers 리스트를 풀어서 하나씩 넣는다는 의미. (1, 2, 3, 4)

numbers

 

 

  • dictionary에서의 활용
def set_profile(**kwargs):
    profile = {}
    profile["name"] = kwargs.get("name", "-")
    profile["gender"] = kwargs.get("gender", "-")
    profile["birthday"] = kwargs.get("birthday", "-")
    profile["age"] = kwargs.get("age", "-")
    profile["phone"] = kwargs.get("phone", "-")
    profile["email"] = kwargs.get("email", "-")
    
    return profile

user_profile = {
    "name": "lee",
    "gender": "man",
    "age": 32,
    "birthday": "01/01",
    "email": "python@sparta.com",
}

# 함수에 인자 넣을 때에도 ** 붙여서 사용
print(set_profile(**user_profile))


""" 아래 코드와 동일
profile = set_profile(
    name="lee",
    gender="man",
    age=32,
    birthday="01/01",
    email="python@sparta.com",
)
"""

# result print
"""
{
    'name': 'lee',
    'gender': 'man',
    'birthday': '01/01',
    'age': 32,
    'phone': '-',
    'email': 'python@sparta.com'
}
"""

**kwargs는 키워드 인자 목록을 받는다. 다른 이름 써도 상관 없지만 통상적으로 keyword arguments의 *kwargs를 사용

kwargs.get("name", "-") 는 "name" 키 값의 value가 없으면 "-" 를 value에 넣어준다는 의미.

 

 

 

# 둘 다 + 다른 것도 함께 사용 가능!

def sample (a, b, *args, **kwargs):
    print(a)
    print(b)
    print(args)
    print(kwargs)
    
    

sample(1, 2, 3, 4, test="a", key="abc", test_key="test_value")


""" 출력

1
2
(3, 4)
{'test': 'a', 'key': 'abc', 'test_key': 'test_value'}

"""

args는 튜플로 설정되고, kwargs는 딕셔너리로 설정되었다.


 

class 심화 

  • __init__ 함수 :  인스턴스를 생성할 때 무조건 생성되는 함수
# class에 __init__메소드를 사용할 경우 인스턴스 생성 시 해당 메소드가 실행된다.

class CookieFrame():
    def __init__(self, name):
        print(f"생성 된 과자의 이름은 {name} 입니다!")
        self.name = name

cookie1 = CookieFrame("cookie1") # 생성 된 과자의 이름은 cookie1 입니다!
cookie2 = CookieFrame("cookie2") # 생성 된 과자의 이름은 cookie2 입니다!

인자를 안 적어주면 에러가 발생한다.

 

💡 name=default 이런 식으로  함수에서는(init 함수 말고도), 인자를 안적어주었을 경우의 default 값을 지정할 수 있다.

 

 

  • 상속

python의 class 상속이란, 클래스를 생성할 때 다른 클래스에 선언된 변수, 메소드 등의 기능들을 가져와 사용할 수 있도록 해주는 기능.

 

동일한 코드를 여러 클래스에서 조금씩 수정해 사용하거나 모듈에 내장되어 있는 클래스를 변경할 때 주로 사용.

 

이 때 상속 해주는 클래스부모(parents) 혹은 슈퍼(super) 클래스라 부르며, 상속 받는 클래스자식(child) 혹은 서브(sub) 클래스 라고 부른다.

 

상속을 사용하면 코드를 간소화 시킬 수 있다.

 

  • 상속 받은 클래스를 기반으로 새로운 클래스 만들기
class Monster():
    def __init__(self, hp):
        self.hp = hp
        
    def attack(self, damage):
        self.hp -= damage

    def status_check(self):
        print(f"monster's hp : {self.hp}")

# 인자에(Monster) -> Monster 함수를 상속받음
class FireMonster(Monster):
    def __init__(self, hp):
        self.attribute = "fire"
        # super()를 사용하면 부모 클래스의 코드를 그대로 사용할 수 있습니다.
        # 해당 코드는 self.hp = hp 코드를 실행시키는 것과 동일합니다.
        super().__init__(hp)
    
    # 부모 클래스에 존재하는 status_check 메소드를 overriding 합니다.
    def status_check(self):
        print(f"fire monster's hp : {self.hp}")
        
class IceMonster(Monster):
    def __init__(self, hp):
        self.attribute = "ice"
        super().__init__(hp)
    
    def status_check(self):
        print(f"ice monster's hp : {self.hp}")
        
fire_monster = FireMonster(hp=100)
# FireMonster 클래스에는 attack 메소드가 없지만
# 부모 클래스에서 상속받았기 때문에 별도의 선언 없이 사용 가능합니다.
fire_monster.attack(20)
fire_monster.status_check()

ice_monster = IceMonster(hp=200)
ice_monster.attack(50)
ice_monster.status_check()

몬스터마다 attack(), status_check() 함수가 다 들어가면 코드 관리도 힘들고, 보기도 좋지 않을 것이다.

이럴 때 상속을 사용하면, 같은 메소드를 따로 선언하지 않아도 상속받아 사용할 수 있다.

변경이 필요할 경우오버라이딩(overriding)을 하자.

 

Q: 파이썬에서 부모클래스를 상속받았으면, 자식클래스의 init함수에서 무조건 super().__init__()를 작성해줘야해?

A: 파이썬에서 자식 클래스가 부모 클래스를 상속받을 때, 자식 클래스의 '__init__' 메서드에서 'super().__init__()'를 호출하는 것은 선택 사항입니다. 그러나 특정 상황에서는 매우 중요할 수 있습니다. 

언제 super().__init__()를 사용해야 하는가?
1. 부모 클래스의 초기화가 필요한 경우: 만약 부모 클래스의 __init__ 메서드가 자식 클래스에서 필요한 초기화 작업을 수행한다면, super().__init__()를 호출해야 합니다. 그렇지 않으면 부모 클래스의 초기화 코드가 실행되지 않아 예상치 못한 동작을 초래할 수 있습니다.

2. 다중 상속을 사용하는 경우: 다중 상속을 사용하는 경우, super()는 부모 클래스의 초기화를 올바른 순서(MRO: Method Resolution Order)로 호출하는 데 도움이 됩니다.

부모 클래스의 초기화가 필요하지 않은 경우
class Parent:
    def __init__(self):
        print("Parent initialized")

class Child(Parent):
    def __init__(self):
        print("Child initialized")

# 사용 예시
child = Child()  # 출력: Child initialized​

 

 

  • 상속 받은 클래스의 특정 코드를 변경해 사용하기
class Calc:
    def _print_zero_division_error(self):
        print("can't be division by zero")
        
    def plus(self, num1, num2):
        ...

    def minus(self, num1, num2):
        ...

    def divide(self, num1, num2):
        if num2 == 0:
            self._print_zero_division_error()
            return False
        ...

    def multiply(self, num1, num2):
        ...

calc = Calc()
calc.divide(5, 0)
# result print
"""
can't be division by zero
"""

해당 계산기 코드에서는 0으로 나눴을 때 영어로 에러를 출력해주고 있다.

 

print를 영어가 아닌 한글로 하고 싶을 때,

상속을 활용하면 코드를 다시 만들거나 모듈 내 코드를 변경하지 않고 원하는 코드를 수정할 수 있다.

 

ctrl + 클릭 하면, 코드의 구현부 코드를 확인 가능하다.

다른 사람이 짠 Calc 코드를 import 해서 사용 중이라 가정했을 때,

모듈에서 _print_zero_Error() 코드를 수정해줘도 되지만, 모듈에 있는 코드를 건드리는 행위는 가능하면 하지않는 것이 좋다.

원래 되는 게 안될 수도 있고, 업데이트된 모듈을 설치했을 때 문제가 생길 수도 있음. 암튼 많은 문제를 일으킬 가능성이 농후하다.

 

=> 상속받아 사용하면 이 코드 수정 필요 없이 사용 가능!! (오버라이딩)

class CustomCalc(Calc):
    def _print_zero_division_error(self):
        print("0으로는 나눌 수 없습니다.")

calc = CustomCalc()
calc.divide(5, 0)
"""
0으로는 나눌 수 없습니다.
"""

 

 


 

객체(object) 다루기

 

클래스를 과자 틀, 클래스를 사용해 만들어진 과자를 인스턴스(instance)라고 이해하면 된다.

객체와 인스턴스는 동일한 용어이며, CookieFrame 클래스를 사용해 생성된 cookie를 “객체” 혹은 “CookieFrame의 인스턴스”라고 표현한다.

 

객체라는 개념이 생소할 수 있겠지만, 우리는 알게 모르게 계속해서 객체를 사용해 왔다.

예를 들어 지금까지 사용했던 list, dict와 같은 자료형 데이터를 생성하고 활했던 것들이 모두 해당 클래스의 객체를 생성하고 메소드를 활용하는 과정이였다.

 

datetime 모듈을 통해 객체를 분석하고 활용하는 방법을 알아보자.

객체에서 사용 가능한 메소드들은 함수의 리턴 타입을 확인하는 방법과 동일하게 검색, docstring, 구현 코드 등을 확인하여 찾을 수 있다.

from datetime import datetime

now = datetime.now() # 현재 시간이 담긴 datetime의 객체(object) 생성
print(type(now)) # <class 'datetime.datetime'>

datetime 구현 코드에서 사용 가능한 메소드들을 확인할 수 있다.

 

 

 

 

 


 

스파르타 내배캠 커리큘럼은 정말 좋은 것 같다.

변수 유효 범위 등은 매번 배웠지만 헷갈리고, 중요한 부분인데 유익했다.

오프라인이라 강의실 대관료를 아낄 수 있어 그 예산이 전부 강의의 품질로 가는 것일까?