[Python] Python 기초 복습

Hyunjun Kim·2025년 4월 15일
0

Data_Engineering

목록 보기
29/153

1 변수, 상수, 리터럴

1.3 리터럴 (literal)

파이썬에서 리터럴은, 변수나 상수에 할당되는 원본 데이터(raw data)를 말한다. 이 데이터 자체는 변경되지 않는다.

1.3.1 숫자 리터럴

정수 리터럴, 실수 리터럴, 복소수 리터럴 3가지가 있다.

  • 정수 리터럴 : 0b로 시작하면 2진수, 0o로 시작하면 8진수 ,0~9로 시작하면 10진수, - 0x로 시작하면 16진수
  • 실수 리터럴 : 소숫점을 포함하거나 e를 포함한다.
  • 복소수 리터럴 : j로 끝나면 복소수의 허수를 나타냅니다.

1.3.5 컬렉션 리터럴

자료형은 다음장에서 자세하게 배우게 됩니다.

  • [ ... ]로 감싸져 있으면 list자료형
  • ( ... )로 감싸져 있으면 tuple자료형
  • { 키:값, ... }로 감싸져 있으면 dictionary자료형
  • { ... }로 감싸져 있으면 set자료형

5 반복문

5.3 for loop

for 문은 다음과 같이 사용할 수 있다.

for 변수명 in Collection:
	반복 실행할 명령문
else:
	반복 종료될때 실행되는 명령문

for 에도 else 써서 반복 종료시 실행되는 명령문 작성 가능.

6 함수

6.5 *args / **kwargs

6.5.1 args

  • 여러개의 인자를 받을 때 * 를 인자에 붙여 사용한다.
  • 주로 arguments 의 약자로 *args 를 이용한다.
  • *args 로 인자를 받으면 함수안에서 args튜플로 사용할 수 있다.
def first_name(*names):
	for name in names:
		print(name[1:])
first_name('차범근', '박지성', '손흥민')

6.5.2 kwargs

  • keyword argument 를 인자로 받을때 ** 를 인자에 붙여 사용한다.
  • keyword argument 의 약자로 **kwargs 를 이용한다.
  • kwargs 는 함수내에서 사전으로 사용되며 param=valuekey,value 쌍이 된다.
def name_value(**kwargs):
	for key, val in kwargs.items():
		print(key, val)
name_value(name="Paul", age="10")

6.9 First-class citizen

일급 객체는 객체지향프로그래밍에서 사용되는 개념 중 하나로 아래의 조건을 만족하는 객체를 의미한다.

  • 변수 혹은 자료구조 안에 담을 수 있어야 한다.
  • 매개변수로 전달할 수 있어야 한다.
  • 리턴값으로 사용될 수 있어야 한다.

Python 에서 함수는 First-Class citizen 다.
아래에서 예제로 함수가 어떻게 First-Class citizen 인지 살펴보자.

6.9.1 변수 혹은 자료구조 안에 담을 수 있어야 한다

def add(a, b):
	return a + b

add2 = add # 함수를 변수에 담을 수 있다.
print(add2(12, 7)) # 19
print(add1(12, 7)) # 19

def mul(a, b):
	return a * b

cal = [add, mul] # 함수를 자료구조에 담을 수 있다.
for i in cal: # 함수를 i 변수에 할당할 수 있음
	print(i(7, 12))

6.9.2 매개변수로 전달할 수 있어야 한다

def add(a, b):
	return a + b

def add_manager(func, a, b): # 함수를 매개변수로 받음
	print(f"add {a} + {b}")
	return func(a, b)
    
res = add_manager(add, 7, 19)
print(res)

6.9.3 리턴값으로 사용될 수 있어야 한다. (함수를 함수내에서 선언할 수 있어야 한다.)

def hello(name): # 1
	def printer(): # 2 
		print(f"Hello {name}!") # 3
	return printer # 4
func = hello("Fox") # 5
func() # 6

6.10 closure

클로저는 어떤 함수의 내부 함수가 외부 함수의 변수를 참조 할때 외부 함수가 종료된 후에도 내부 함수가 외부함수의 변수를 참조할 수 있도록 어딘가에 저장하는 함수를 의미한다.

  • 어떤 함수의 내부 함수일 것
  • 내부 함수가 외부 함수의 변수를 참조할 것
  • 외부 함수가 내부 함수를 리턴할 것

6.10.1 예제 1

def hello(msg):
	message = "Hello, " + msg

	def say():
		print(message)
	return say

f = hello('Python') # hello 함수가 say 함수를 반환
f() # Hello, Python 출력

6.10.2 예제 2

def calulate_4(num):
    sum_1 = 4 + num
    print(sum_1)

    def add_5():
        print(add(sum_1, 5))
    
    return add_5

add_5 = calulate_4(10) #14
add_5()  # 19

hello 함수가 say 함수를 리턴하면서 메모리 스택에서 삭제된다. 이때 hello 함수의 내부 변수였던 message 는 삭제되지 않고 say 함수에 남아있다. 이는 중첩함수인 say 가 외부 함수의 변수인 message를 참조하기 때문에 message 변수와 say 환경을 저장하는 클로저가 동적으로 생성되었고 f 가 실행될때는 해당 클로저를 참조하여 message 값을 실행하기 때문이다.

6.11 decorator

데코레이터는 함수를 인자로 받아 꾸며준 후 다시 함수로 리턴하는 함수다.
여기서 꾸며준다는 의미는 인자로 받은 함수 실행 전 주로 특정 로직을 추가하거나 하는 행동이다.
데코레이터를 작성하고 @데코레이터 방식으로 함수를 데코레이팅 할 수 있다.

아래는 함수의 실행시간을 측정해주는 데코레이터를 작성한 코드다.

import time

def logging_duration(orig_func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = orig_func(*args, **kwargs)
        end_time = time.time()
        print(f"{orig_func.__name__} duration : {end_time - start_time} sec")
        return result
    return wrapper


@logging_duration
def hello_and_sleep():
    time.sleep(1)
    print('heelo')

@logging_duration
def hello_and_slee2():
    time.sleep(2)
    print('heelo2')

hello_and_sleep()
hello_and_slee2()

7 객체지향언어

7.4 생성자 (constructor)

  • 생성자는 인스턴스가 생성될 때 사용되는 '인스턴스 초기화 메소드'다. 즉 클래스이름 과 같은 키워드로 해당 클래스의 인스턴스가 새로 생성될 때, 자동으로 호출되는 메소드다. 이 생성자를 이용해서 인스턴스가 생성될 때 수행할 동작을 코드로 짤 수 있는데, 대표적으로 인스턴스 변수를 초기화 하는 용도로 사용한다.
  • Python 에서는 __init__ 을 이용하여 클래스에서 생성자를 정의할 수 있다.
  • 객체에 초깃값을 설정해야 할 필요가 있을 때는 메서드를 호출 하여 초깃값을 설정하기보다는 생성자를 구현하는 것이 안전한 방법이다. 생성자란 객체가 생성될 때 자동으로 호출되는 메서드를 의미한다.
class Person:
	def __init__(self, first_name, last_name, age):
		self.first_name = first_name
		self.last_name = last_name
		self.age = age
	
    def print_age(self):
		print(self.age)
	
    def full_name(self):
		return self.last_name + self.first_name

	def introduce(self):
		print(f"안녕하세요 {self.full_name()} 입니다.")

person1 = Person("철수", "김", 27)
person2 = Person("영희", "이", 28)
person1.print_age()
person2.print_age()

__init__ 의 이름으로 정의된 메서드는 정의하게 되면 인스턴스를 생성할때 동시에 실행된다.
위의 예제에서 __init__ 은 person1 = Person("철수", "김", 27) 로 인스턴스를 생성하는 시점에 실행된다. 다음과 같이 __init__ 을 정의해보자.

...
def __init__(self, first_name, last_name, age):
	self.first_name = first_name
	self.last_name = last_name
	self.age = age
	print(f"{last_name}{first_name} : {age}")
...

person1 = Person("철수", "김", 27) # 김철수 : 27
person2 = Person("영희", "이", 28) # 이영희 : 28

위와 같이 __init__ 메서드를 정의하면 인스턴스를 생성하는 시점에 이름 : 나이 에 대한 정보가 출력된다.
추가로 함수의 매게변수에 초기값을 선언하는 방법을 이용해 생성자 메서드에 초기값을 선언할 수 있다.

7.5 상속

7.5.1 상속

어떤 클래스를 만들때 다른 클래스의 기능을 물려받을 수 있게 만드는 것을 상속이라고 한다. 이번에는 상속 개념을 사용해 우리가 만든 Person 클래스를 상속받은 Developer 클래스를 생성해 보자.

class Developer(Person):
	pass
...

클래스를 상속하기 위해서는 다음처럼 클래스 이름 뒤 괄호안에 상속할 클래스 이름을 넣어주면 된다.
Developer 클래스는 Person 클래스를 상속했으므로, Person 클래스의 모든 기능을 사용할 수 있다.

developer1 = Developer("철수", "김", 27)
developer1.print_age() # 27
developer1.introduce() # 안녕하세요 김철수 입니다.

상속받은 Person 클래스의 기능을 모두 사용할 수 있음을 확인할 수 있다.
보통 상속은 기존 클래스를 변경하지 않고 기능을 추가하거나 기존 기능을 변경하려고 할 때 사용한다.
"클래스에 기능을 추가하고 싶으면 기존 클래스를 변경하면 되지않나?" 라는 의문이 들 수 있지만, 기존 클래스가 라이브러리 형태로 제공되거나 수정이 허용되지 않는 상황이라면 상속을 사용해야 한다.

파이썬은 자바와 다르게 다중 상속이 가능한 언어다.

7.5.2 메소드 오버라이딩

  • 메소드 오버라이딩은 부모 클래스의 메소드를 자식 클래스에서 재정의 하는 것이다.
  • Person 클래스의 introduce 메소드를 재정의 해보자.
  • super() 라는 키워드를 사용하면 자식클래스 내에서도 부모클래스를 호출 할 수 있다.
class Developer(Person):
	def introduce(self):
		super().introduce()
		print(f"안녕하세요 개발자 {self.full_name()} 입니다.")

developer1 = Developer("철수", "김", 27)
developer1.print_age()
developer1.introduce()
  • 결과를 확인해보면 부모클래스인 Person 클래스의 introduce() 또한 실행이 되었음을 확인할 수 있다.

7.6 추상클래스

7.6.1 추상클래스(abstract class) 란

  • 추상클래스란 미구현 추상메소드를 한개 이상 가지는 클래스다.
  • 추상클래스를 상속한 자식클래스에서 해당 추상 메소드를 반드시 구현하도록 강제한다.
  • abc 모듈을 import 하여 ABCMeta 를 상속받아 아래와 같이 사용한다.
from abc import *

class 추상클래스명(metaclass=ABCMeta):
	@abstractmethod
	def 추상메소드(self):
		pass

7.6.2 추상클래스(abstract class) 사용

  • Person 클래스를 추상클래스로 선언하고, 추상 메소드를 추가해보자.
class Person(metaclass=ABCMeta):
	def __init__(self, first_name, last_name, age):
		self.first_name = first_name
		self.last_name = last_name
		self.age = age

	def print_age(self):
		print(self.age)

	def full_name(self):
		return self.last_name + self.first_name

	def introduce(self):
		print(f"안녕하세요 {self.full_name()} 입니다.")

	@abstractmethod
	def print_job(self):
		print("직업은?")

위와같이 Person 객체에 추상메소드를 선언한경우 Person을 상속받은 Developer 객체에서 추상메소드를 재정의 해야한다.

class Developer(Person):
	def print_job(self):
		print("개발자로 일하고 있다.")

class ProductManager(Person):
	def print_job(self):
		print("PM으로 일하고 있다.")

7.7 Magic 메소드

7.7.1 Magic 메소드란?

  • 특수목적 메소드 혹은 Special 메소드라고 불린다.
  • 더블 언더스코어로 둘러싸여 있다.
  • 산술연산, print 등 특수한 상황에 어떤 결과값을 내야 하는지를 정의할 수 있다.

7.7.2 Magic 메소드 종류

자주 사용되는 Magic 메소드에 대해 알아보자.

  • __new__ : 새로운 객체를 만들 때 제일 처음으로 실행되는 메소드
  • __init__ : 객체 생성자, 객체를 생성할 때 사용됨
  • __str__ : str(객체) 의 결과값을 정의
  • __repr__ : 객체를 표현할때 사용하는 문자열 정의가능
  • __add__ : 두개의 객체를 더하려고 할때 사용
  • __and__ : & 연산자를 사용하려고 할때 실행
  • __bool__ : 객체에 대해 부울 검사를 수행할 때 실행됨
  • __mul__ : * 연산자를 사용하려고 할때 사용
  • __mod__ : / 연산자를 사용하려고 할때 사용
  • __le__ : ≤ 에 사용
  • __ge__ : ≥ 에 사용
  • __del__ : 객체를 없앨때 호출되는 메소드
  • __len__ : 객체의 길이를 반환
  • __doc__ : Docstring 을 출력하는 메소드

7.7.3 Magic 메소드 예시

Person 객체에서 나이를 이용하여 __add____ge__ 를 구현한 예시는 다음과 같다.

class Person:
	def __init__(self, name, age):
		self.name = name
		self.age = age

	def __add__(self, other):
		return self.age + other.age

	def __ge__(self, other):
		return self.age >= other.age

person1 = Person("철수", 27)
person2 = Person("영희", 28)

print(person1 + person2) # 55
print(person1 >= person2) # False

7.8 접근제어자 (access modifier)

7.8.1 메소드란?

  • C++, Java와 같이 클래식한 object-oriented 언어에서는 public, private, protected와 같은 키워드로 class의 member에 대한 접근을 제어한다.
  • Private member : class 외부에서 접근이 불가능하며 class 내부에서만 접근될 수 있다.
  • Public member : class 외부에서도 접근할 수 있다.
  • Protected member : 오직 해당 class와 그 class를 상속받은 child class만이 접근할 수 있다.
  • Python은 instance variable과 method에 대해서 접근 제한을 하는 방식이 따로 없다.
  • Python 에서는 맴버변수나 메소드의 이름 앞에 한개 또는 2개의 _(underscore)를 붙여서 protected와 private으로 구분하기로 약속한다.
  • 실제 실행하거나 빌드할 때 접근제어자에 부적합한 접근에 대한 검증을 거치지 않는다.
  • 언더스코어를 이용한 접근제어자 표현은 마치 객체와 함수명에 대한 약속과 같이 Python 개발자들 끼리의 약속이다.

7.8.2 Public

Public attribute 의 경우 언더스코어를 붙이지 않는다

class Person:
	def __init__(self, name, age):
		self.name = name
		self.age = age

7.8.3 Protected

Protected attribute 의 경우 한개의 언더스코어를 이용한다.

class Person:
	def __init__(self, name, age):
		self._name = name
		self._age = age

7.8.4 Private

Private attribute 의 경우 두개의 언더스코어를 이용하여 표현한다.

class Person:
	def __init__(self, name, age):
		self.__name = name
		self.__age = age

8 예외처리

8.3 에러 발생시키기

  • 프로그래밍을 하다 보면 종종 오류를 일부러 발생시켜야 하는 경우도 생긴다.
  • 파이썬은 raise 명령어를 사용해 오류를 강제로 발생시킬 수 있다.

예를 들어 Person 클래스를 상속받는 자식 클래스는 반드시 introduce 메소드를 구현해야 한다고 생각해 보자.

class Person:
	def introduce(self):
		raise NotImplementedError

Person 클래스를 상속받은 자식 클래스가 introduce 를 오버라이딩 하여 에러발생 부분을 없애지 않는다면 자연스럽게 NotImplementedError 가 발생한다.

class Developer(Bird):
	pass

developer1 = Developer()
developer1.introduce()

8.4 Custom 예외 만들기

  • 프로그램 수행 도중 특수한 경우에만 예외 처리를 하기 위해서 종종 예외를 만들어서 사용한다.
  • 예외는 다음과 같이 파이썬 내장 클래스인 Exception 클래스를 상속하여 만들 수 있다.

Person 클래스를 만들때 인자로 받는 age 값이 음수일때 발생시키는 예외를 작성해 보자.

class AgeError(Exception):
	def __str__(self):
		return "나이는 항상 자연수값을 가져야 한다."

class Person:
	def __init__(self, age):
		if age <= 0:
			raise AgeError
		self.age = age

10 날짜와 시간 다루기

10.2 datetime.timedelta

날짜와 시간을 연산할때는 timedelta 클래스를 이용한다. 두개의 datetime 클래스 객체의 차이의 결과가 timedelta 클래스로 반환된다.

timedelta 클래스는 다음과 같은 속성과 메소드를 가진다.

  • days : 일수
  • seconds : 초
  • microseconds : 마이크로초
  • total_seconds() : 모든 속성을 초 단위로 모아서 반환
import datetime

dt1 = datetime.datetime(2016, 3, 11, 11)
dt2 = datetime.datetime(2022, 6, 2, 11)
td = dt1 - dt2
td
print(td.days, td.seconds, td.microseconds)
print(td.total_seconds())

delta = datetime.timedelta(days=90, seconds=3600)
dt0 = dt1 + delta

13 Logger

13.1 logging 모듈

Python 에서 기본으로 제공하는 logging 모듈을 이용해 프로그램 실행 중 로그를 남길 수 있다.

import logging

특정 이벤트가 발생했을 때 로그를 심게 되는데, 이벤트의 심각성에 따라 logging level을 설정할 수 있다. 표준 levels 로는 아래 다섯가지가 있다.

  • DEBUG
  • INFO
  • WARNING
  • ERROR
  • CRITICAL
import logging
logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical message')
# ...
# WARNING:root:This is a warning message
# ERROR:root:This is an error message
# CRITICAL:root:This is a critical message

logging 으로 생성된 메세지는 각 logging level 에 대한 정보도 함께 포함하고 있다.

13.2 기본 설정값

logging 의 설정값을 정의하는데 basicConfig() 메소드를 사용할 수 있다.
basicConfig() 에 사용할 수 있는 parameter 는 다음과 같다.

  • level : logger에서 공개하고 싶은 level을 설정할 수 있다. 예를 들어 warning 으로 하면 info 등급의 로깅은 출력되지 않는다.
  • filename : 로그를 적을 파일이름을 명시할 수 있다.
  • filemode : 파일이름이 주어졌을때 파일모드를 정할 수 있다. default 값은 a 다.
  • format : log message 의 포맷을 결정한다.
import logging

logging.basicConfig(filename='app.log', filemode='w', format='%(name)s - %(levelname)s - %(message)s')
logging.warning('This will get logged to a file')

# app.log 파일에 'root - ERROR - This will get logged to a file' 라고 출력된것을 확인할 수 있다.

13.3 출력 결과 Formatting

로그를 작성할때 사용할 수 있는 몇가지 기본 요소들이 있다. 그 요소들을 이용해 logging 포멧을 설정할 수 있다.

  • format에서 사용할 수 있는 설정 속성 (attributes) 리스트 매뉴얼
  • process : process id
  • levelname : severity level
  • message : 로깅 메세지
  • asctime : 24시간 기준 시계로 시간 출력
import logging
logging.basicConfig(format='%(asctime)s.%(msecs)03d - %(levelname)s - %(process)d- %(message)s', datefmt='%d-%b-%y %H:%M:%S')
logging.warning('Admin logged out')

## 31-Dec-22 20:12:06.288 - WARNING - 18472 - Admin logged in

13.4 Stack Traces 캡쳐

로깅 모듈은 모든 프로그램 내에서 생성되는 stack traces 를 캡쳐하는 기능을 제공한다. 예를 들어 예외와 관련된 정보는 exc_info=True 를 이용하여 출력할 수 있다.

import logging

a = 5
b = 0

try:
	c = a / b
except Exception as e:
	logging.error("Exception occurred", exc_info=True)

위 코드를 실행하면 다음과 같은 결과가 출력된다.

ERROR:root:Exception occurred
Traceback (most recent call last):
	File "exceptions.py", line 6, in <module>
		c = a / b
ZeroDivisionError: division by zero
[Finished in 0.2s]

exc_info=True 외에 logging.exception() 메소드를 이용해 동일한 기능을 수행할 수 있다.
logging.exception() 메소드는 ERROR level 의 로그와 stack traces 를 동시에 출력한다.

import logging

a = 5
b = 0

try:
	c = a / b
except Exception as e:
	logging.exception("Exception occurred")

위 코드의 실행결과는 다음과 같다.

ERROR:root:Exception occurred
Traceback (most recent call last):
	File "exceptions.py", line 6, in <module>
		c = a / b
ZeroDivisionError: division by zero
[Finished in 0.2s]

13.5 logging 모듈의 클래스와 함수들

지금까지 logging.debug() 와 같이 함수가 직접 호출될 때 마다 로깅 모듈에서 사용하는 root 라는 기본 로거를 이용했다. 프로그램에 서로 다른 이름의 로거를 사용해야 되는 순간에 어떻게 해야하는지 logging 모듈의 클래스와 함수를 살펴보자.

  • Logger : 함수를 호출하기 위해 직접적으로 사용되는 클래스다.
  • LogRecord : logging 작업에 관련된 모든 정보를 담고 있는 클래스다.
  • Handler : HandlerLogRecord 를 콘솔이나 파일과 같은 필요한 출력 대상으로 보낸다.
  • Formatter : Formatter 를 이용해 출력 형식을 지정한다.
import logging

logger = logging.getLogger('example_logger')
# example_logger 이름의 Logger 객체를 반환한다
logger.warning('This is a warning')

13.6 Handler 사용하기

Handler 는 로거를 구성하고 로그가 생성될 때 여러 위치로 로그를 보내려는 경우에 사용된다. Handler 는 로그 메시지를 표준 출력 스트림, 파일, HTTP를 이용해 다른 서버 혹은 SMTP를 통해 이메일로 보낸다.

생성한 로거에는 하나 이상의 Handler가 있을 수 있다. 즉, 로그 파일에 저장하고 이메일을 통해 보낼 수도 있다.

로거와 마찬가지로 Handler 에서 심각도 수준을 설정할 수도 있다. 이는 동일한 로거에 대해 여러 처리기를 설정하지만 각각에 대해 다른 심각도 수준을 원하는 경우에 유용하다.

예를 들어, 레벨이 WARNING 이상인 로그를 콘솔에 기록하기를 원할 수 있지만 레벨이 ERROR 이상인 모든 로그도 파일에 저장해야 한다. 다음은 이를 수행하는 프로그램이다.

import logging

# 새로운 커스텀 로거 생성
logger = logging.getLogger(__name__)

# handler 생성
c_handler = logging.StreamHandler()
f_handler = logging.FileHandler('file.log')
c_handler.setLevel(logging.WARNING)
f_handler.setLevel(logging.ERROR)

# formatter 를 생성하여 handler 에 부착
c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
f_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
c_handler.setFormatter(c_format)
f_handler.setFormatter(f_format)

# handler 를 로거에 부착
logger.addHandler(c_handler)
logger.addHandler(f_handler

logger.warning('This is a warning')
logger.error('This is an error')

13.7 Other Configuration

fileConfig() 혹은 dictConfig() 를 사용하여 로그 속성을 정의할 수 있다.
아래 두가지 예제를 통해 학습해보자.

13.7.1 fileConfig()

  • 디렉토리에 file.conf 를 생성하고 에 다음 설정 정보를 입력하자
[loggers]
keys=root,sampleLogger

[handlers]
keys=consoleHandler

[formatters]
keys=sampleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_sampleLogger]
level=DEBUG
handlers=consoleHandler
qualname=sampleLogger
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=sampleFormatter
args=(sys.stdout,)

[formatter_sampleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
  • fileConfig() 를 이용한 logger 구성 설정
import logging
import logging.config

logging.config.fileConfig(fname='file.conf', disable_existing_loggers=False)

logger = logging.getLogger(__name__)

logger.debug('This is a debug message')
# 2018-07-13 13:57:45,467 - __main__ - DEBUG - This is a debug message

13.7.2 dictConfig()

config.yaml 파일을 생성하고 다음 값들을 입력하자

version: 1

formatters:
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: simple
    stream: ext://sys.stdout

loggers:
  sampleLogger:
    level: DEBUG
    handlers: [console]
    propagate: no

root:
  level: DEBUG
  handlers: [console]

yaml format 에 대한 내용은 다음 링크를 참고

생성한 yaml 파일을 읽어 dict 객체를 생성하고 이를 이용해 logger 를 설정할 수 있다.

import logging
import logging.config
import yaml
with open('config.yaml', 'r') as f:
	config = yaml.safe_load(f.read())
	logging.config.dictConfig(config)

logger = logging.getLogger(__name__)

logger.debug('This is a debug message')
profile
Data Analytics Engineer 가 되

0개의 댓글