이번 포스트에서는 Python의 csv 모듈과 dataclass를 사용하여 CSV 파일에서 국가 데이터를 불러와 Country 객체로 관리하는 방법을 다룰 것입니다. 하지만 진행하면서 몇 가지 실수와 오류를 만나게 되었고, 그에 대한 해결 과정도 함께 공유하려고 합니다.
CSV 파일에서 국가 정보(예: GDP, 생명 기대치, 밀도, 위도, 경도 등)를 읽어 Country 객체를 만들고, 이를 관리하는 클래스를 구현하는 것이 목표였습니다.
먼저, 국가의 정보를 담을 Country 클래스를 만들었습니다. 이 클래스는 국가의 이름, GDP, 생명 기대치, 밀도, 위도, 경도를 저장합니다. Python의 dataclass를 사용하여 간편하게 데이터를 저장할 수 있도록 했습니다.
from dataclasses import dataclass
@dataclass
class Country:
name: str
gdp: float
life_expectancy: float
density: float
lat: float
lon: float
CSV에서 가져오는 데이터에는 불필요한 기호가 포함되어 있을 수 있습니다. 예를 들어, GDP 값에는 쉼표(,)나 달러 기호($)가 포함될 수 있습니다. 이를 처리하기 위해 __clean_numeric_data라는 메서드를 만들었습니다.
def __clean_numeric_data(self, value: str) -> float:
try:
cleaned = value.strip().replace(',', '').replace('$', '').replace('%', '')
if cleaned == '':
return 0.0
return float(cleaned)
except (ValueError, AttributeError):
return 0.0
이 함수는 데이터를 클린징한 후 숫자로 변환합니다. 데이터에 오류가 있을 경우, 0.0을 반환하여 예외를 처리합니다.
CountryStastic 클래스에서는 __load_data 메서드를 사용하여 CSV 파일을 읽고, 각 행을 Country 객체로 변환하여 리스트에 추가합니다. CSV 파일에서 각 국가의 정보가 잘 들어오도록 하였습니다.
import csv
class CountryStastic:
def __init__(self):
self.countries = []
def __clean_numeric_data(self, value: str) -> float:
# 위에서 정의한 __clean_numeric_data 함수
def __load_data(self, filename: str):
with open(filename, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
header_row = next(reader)
for line in reader:
try:
gdp = self.__clean_numeric_data(line['GDP'])
life_expectancy = self.__clean_numeric_data(line['Life expectancy'])
density = self.__clean_numeric_data(line['Density (P/Km2)'])
lat = self.__clean_numeric_data(line['Latitude'])
lon = self.__clean_numeric_data(line['Longitude'])
except Exception as e:
print(e, line)
else:
country = Country(line['Country'], gdp, life_expectancy, density, lat, lon)
self.countries.append(country)
여기서 중요한 점은, 각 국가의 데이터를 Country 객체로 변환할 때 모든 필드가 필요하다는 점입니다. 특히 GDP 외에도 생명 기대치, 밀도, 위도, 경도를 포함해야 했습니다.
처음에 Country 객체를 만들 때, 생성자에 name과 gdp만 넣고 나머지 값들을 빼먹는 실수를 했습니다. Country 클래스의 생성자는 name, gdp, life_expectancy, density, lat, lon을 모두 필요로 하기 때문에, 이를 제대로 전달하지 않으면 TypeError가 발생합니다.
TypeError: __init__() missing 4 required positional arguments: 'life_expectancy', 'density', 'lat', and 'lon'
Country 객체를 생성할 때, 모든 필드를 제공해야 한다는 점을 놓친 것을 깨닫고, life_expectancy, density, lat, lon 값을 추가해주었습니다.
country = Country(line['Country'], gdp, life_expectancy, density, lat, lon)
self 누락__load_data 메서드에서 __clean_numeric_data 메서드를 호출할 때 self를 누락하는 실수가 있었습니다. self.__clean_numeric_data로 호출해야 하는데, __clean_numeric_data만 호출하였기 때문에 NameError가 발생했습니다.
NameError: name '__clean_numeric_data' is not defined
__clean_numeric_data를 클래스 내부의 메서드로 사용하려면 반드시 self를 붙여야 한다는 점을 확인하고, 이를 수정했습니다.
gdp = self.__clean_numeric_data(line['GDP'])
lambda)top_5_dap 메서드를 작성할 때, lambda 함수의 이름을 lamda로 잘못 작성하는 실수가 있었습니다. 이는 Python에서 lambda 키워드가 잘못 사용된 예입니다.
NameError: name 'lamda' is not defined
lambda로 수정하여 정상적으로 작동하도록 했습니다.
return sorted(self.countries, key=lambda x: x.gdp, reverse=True)[:5]
import csv
from dataclasses import dataclass
@dataclass
class Country:
name: str
gdp: float
life_expectancy: float
density: float
lat: float
lon: float
class CountryStastic:
def __init__(self):
self.countries = []
def __clean_numeric_data(self, value: str) -> float:
try:
cleaned = value.strip().replace(',', '').replace('$', '').replace('%', '')
if cleaned == '':
return 0.0
return float(cleaned)
except (ValueError, AttributeError):
return 0.0
def __load_data(self, filename: str):
with open(filename, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
header_row = next(reader)
for line in reader:
try:
gdp = self.__clean_numeric_data(line['GDP'])
life_expectancy = self.__clean_numeric_data(line['Life expectancy'])
density = self.__clean_numeric_data(line['Density (P/Km2)'])
lat = self.__clean_numeric_data(line['Latitude'])
lon = self.__clean_numeric_data(line['Longitude'])
except Exception as e:
print(e, line)
else:
country = Country(line['Country'], gdp, life_expectancy, density, lat, lon)
self.countries.append(country)
def top_5_dap(self):
return sorted(self.countries, key=lambda x: x.gdp, reverse=True)[:5]
# 사용 예시
c = CountryStastic()
c.__load_data('world-data-2023.csv')
print(c.top_5_dap())
이 포스트에서는 CSV 파일에서 국가 정보를 불러오고, 이를 Python 클래스 객체로 관리하는 방법을 소개했습니다. 또한, 코드에서 발생한 여러 실수들을 해결하는 과정을 자세히 다뤘습니다. 처음에는 매개변수 누락, 메서드 호출 오류, 오타 등 여러 가지 문제들이 있었지만, 이를 해결하면서 코드의 안정성을 높일 수 있었습니다.
다음 단계로는 plotly를 사용하여 데이터를 시각화하거나, 데이터를 분석하는 기능을 추가할 수 있습니다.