콘텐츠로 건너뛰기

파이썬의 Named Tuple 사용법

CodeMDD.io

Python에서 namedtuple 사용하여 Pythonic Code 작성하기

Python의 collections 모듈은 튜플을 다룰 때 더욱 Pythonic한 코드를 작성할 수 있도록 하기 위해 특별히 설계된 namedtuple() 팩토리 함수를 제공합니다. namedtuple()을 사용하면, 새로운 불변(immutable) 순차형 타입을 만들 수 있으며, 이러한 타입의 값을 명확한 필드 이름과 도트 표기법을 사용하여 접근할 수 있습니다. 이 기능을 활용하여 코드를 작성해보세요.

이 튜토리얼에서는 다음과 같은 내용을 배웁니다:

  • **namedtuple()**을 사용하여 namedtuple 클래스를 만드는 방법
  • namedtuple고급 기능을 식별하고 활용하는 방법
  • namedtuple 인스턴스를 사용하여 Pythonic 코드를 작성하는 방법
  • namedtuple을 사용해야 할지, 유사한 데이터 구조를 사용해야 할지 결정하는 방법
  • 새로운 기능을 제공하기 위해 namedtuple서브클래스화하는 방법

위의 모든 내용을 모두 알지 못한다면 걱정하지 마세요! 필요한 경우에는 중지하고 위의 자료를 복습할 수 있습니다.

Pythonic Code를 작성하기 위한 namedtuple 사용하기

namedtuple 클래스를 작성하는 가장 간단한 방법은 namedtuple() 팩토리 함수를 사용하는 것입니다. namedtuple() 함수에는 클래스 이름과 필드 이름들을 인자로 전달하여 namedtuple 클래스를 생성할 수 있습니다.

아래의 예제는 namedtuple() 함수를 사용하여 Color 클래스를 생성하는 코드입니다:

from collections import namedtuple
Color = namedtuple('Color', ['red', 'green', 'blue'])

위의 코드에서 Colornamedtuple 클래스의 새로운 인스턴스입니다. 이 클래스는 red, green, blue라는 필드 이름들을 가진 불변한 타입을 생성합니다.

namedtuple 클래스의 인스턴스는 튜플처럼 동작하지만, 필드 이름에 의한 접근이 가능합니다. 예를 들어, 아래와 같이 Color 클래스의 인스턴스를 생성하고 필드 값을 가져올 수 있습니다:

my_color = Color(255, 0, 0)
print(my_color.red) # 255

이렇게 필드 이름을 사용하여 필드 값을 직접 접근할 수 있으므로 코드의 가독성과 유지보수성이 향상됩니다.

namedtuple을 사용한 Tuple과 유사한 클래스 작성하기

namedtuple을 사용하면, 사용자 정의로 구현한 클래스와 동일한 동작을 수행하는 튜플과 유사한 클래스를 작성할 수 있습니다.

namedtuple에 필수 인자 제공하기

namedtuple 클래스를 작성할 때, 필드 이름을 포함하는 리스트를 namedtuple() 함수에 인자로 전달하는 것 이외에도 선택적으로 기본값을 제공할 수 있습니다. 이렇게 하면, 클래스를 인스턴스화할 때 필드 값들을 전달하지 않아도 기본값을 사용할 수 있습니다.

아래의 예제는 Student 클래스를 생성하는 코드입니다. 이 클래스는 nameage라는 필드를 가지며, age 필드의 기본값은 0입니다:

from collections import namedtuple
Student = namedtuple('Student', ['name', 'age'], defaults=[0])

위의 코드에서 defaults 인자를 사용하여 age 필드의 기본값을 설정할 수 있습니다.

Student 클래스의 인스턴스를 생성하는 데 필드값을 입력하지 않으면, name 필드는 빈 문자열('')로 초기화되고 age 필드는 0으로 초기화됩니다:

student1 = Student('Alice')
student2 = Student('Bob', 20)
print(student1) # Student(name='Alice', age=0)
print(student2) # Student(name='Bob', age=20)

위의 예제에서 student1age 필드의 기본값인 0을 사용하여 인스턴스화됩니다.

namedtuple에 선택적 인자 사용하기

namedtuple 클래스를 작성할 때, 선택적인 인자를 사용할 수 있습니다. 이러한 인자는 필드 초기값 또는 필드의 기본값으로 사용할 수 있습니다. 선택적 인자를 사용하려면 namedtuple() 함수에 field_defaults라는 인자를 전달하면 됩니다.

아래의 예제는 Person 클래스를 생성하는 코드입니다. 이 클래스는 nameage라는 필드를 가지며, age 필드의 기본값은 0으로 설정되어 있습니다. 또한, gender 필드는 선택적 인자로 지정됩니다:

from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'gender'], defaults=[0], field_defaults={'gender': 'Unknown'})

위의 예제에서 field_defaults 인자를 사용하여 gender 필드의 기본값을 'Unknown'으로 설정하였습니다.

Person 클래스의 인스턴스를 생성하는 데 필드 값이 입력되지 않으면, name 필드는 빈 문자열('')로 초기화되고, age 필드는 0으로 초기화되며, gender 필드는 'Unknown'으로 초기화됩니다:

person1 = Person('Alice')
person2 = Person('Bob', 20, 'Male')
print(person1) # Person(name='Alice', age=0, gender='Unknown')
print(person2) # Person(name='Bob', age=20, gender='Male')

위의 예제에서 person1age 필드의 기본값인 0gender 필드의 기본값인 'Unknown'을 사용하여 인스턴스화됩니다.

namedtuple 클래스의 추가 기능 탐색하기

namedtuple 클래스는 튜플의 추가 기능을 제공합니다. 이러한 추가 기능 중 일부는 아래에서 자세히 살펴보겠습니다.

이터러블에서 namedtuple 인스턴스 생성하기

namedtuple 클래스는 이터러블 객체에서 인스턴스를 생성할 수 있습니다. 이러한 기능을 사용하려면 ._make() 메서드를 호출하고, 인자로 이터러블 객체를 전달하면 됩니다.

아래의 예제는 리스트를 이용하여 Person 클래스의 인스턴스를 생성하는 코드입니다:

from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'gender'])
person_data = ['Alice', 25, 'Female']
person = Person._make(person_data)
print(person) # Person(name='Alice', age=25, gender='Female')

위의 예제에서 person_data 리스트를 사용하여 Person 클래스의 인스턴스를 생성하였습니다.

namedtuple 인스턴스를 딕셔너리로 변환하기

namedtuple 인스턴스는 .asdict() 메서드를 호출하여 딕셔너리로 변환할 수 있습니다. 이러한 변환은 특히 데이터를 직렬화하거나 저장하는 데 유용할 수 있습니다.

아래의 예제는 Person 클래스의 인스턴스를 딕셔너리로 변환하는 코드입니다:

from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'gender'])
person = Person('Alice', 25, 'Female')
person_dict = person._asdict()
print(person_dict) # {'name': 'Alice', 'age': 25, 'gender': 'Female'}

위의 예제에서 personPerson 클래스의 인스턴스입니다. 이 인스턴스를 .asdict() 메서드를 사용하여 딕셔너리로 변환하였습니다.

기존 namedtuple 인스턴스에서 필드 교체하기

namedtuple 인스턴스는 .._replace() 메서드를 호출하여 필드 값을 변경할 수 있습니다. 이 메서드는 필드의 값을 변경한 새로운 namedtuple 인스턴스를 반환합니다.

아래의 예제는 Person 클래스의 인스턴스를 생성하고, ._replace() 메서드를 사용하여 age 필드의 값을 변경하는 코드입니다:

from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'gender'])
person = Person('Alice', 25, 'Female')
new_person = person._replace(age=30)
print(person) # Person(name='Alice', age=25, gender='Female')
print(new_person) # Person(name='Alice', age=30, gender='Female')

위의 예제에서 personPerson 클래스의 인스턴스입니다. 이 인스턴스에 .replace() 메서드를 호출하여 age 필드의 값을 변경하였습니다.

추가적인 namedtuple 속성 탐색하기

namedtuple 클래스 인스턴스에는 몇 가지 유용한 속성이 더 있습니다. 이러한 속성들을 활용하여 더욱 다양한 작업을 수행할 수 있습니다.

아래의 예제는 Person 클래스의 인스턴스를 생성하고, .fields, .count(), 그리고 .index() 속성을 사용하여 필드에 대한 정보를 가져오는 코드입니다:

from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'gender'])
person = Person('Alice', 25, 'Female')
print(person.fields) # ('name', 'age', 'gender')
print(person.count(25)) # 1
print(person.index('Female')) # 2

위의 예제에서 personPerson 클래스의 인스턴스입니다. 이 인스턴스의 .fields 속성은 namedtuple 클래스에서 정의된 모든 필드 이름들을 튜플로 반환합니다. .count() 메서드는 특정 값을 가진 필드의 수를 반환하며, .index() 메서드는 특정 값이 처음으로 발견된 인덱스를 반환합니다.

namedtuple을 사용하여 Pythonic Code 작성하기

namedtuple은 필드 이름을 사용하여 인덱스 대신에 필드 이름을 사용할 수 있습니다. 이는 코드의 가독성과 유지보수성을 향상시킵니다.

인덱스 대신 필드 이름 사용하기

namedtuple을 사용하는 가장 큰 장점 중 하나는 필드 이름을 사용하여 필드 값을 가져올 수 있다는 점입니다.

예를 들어보면, 아래의 예제에서 Person 클래스의 인스턴스를 생성하고, 필드 이름을 사용하여 필드 값을 가져옵니다:

from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'gender'])
person = Person('Alice', 25, 'Female')
print(person.name) # 'Alice'
print(person.age) # 25
print(person.gender) # 'Female'

위의 예제에서 person 인스턴스의 필드 값을 가져올 때, 필드 이름을 사용하여 필드에 바로 접근할 수 있습니다. 이는 코드의 가독성과 유지보수성을 높이는 데에 도움이 됩니다.

여러 개의 이름 있는 값 반환하기

namedtuple을 사용하면 여러 개의 이름 있는 값을 함수에서 반환할 수 있습니다. 이는 반환되는 값들을 더 표현력이 높은 형태로 전달할 수 있게 도와줍니다.

아래의 예제는 get_person() 함수를 사용하여 Person 클래스의 인스턴스를 반환하는 코드입니다:

from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'gender'])
def get_person():
return Person('Alice', 25, 'Female')
person = get_person()
print(person.name) # 'Alice'
print(person.age) # 25
print(person.gender) # 'Female'

위의 예제에서 get_person() 함수는 Person 클래스의 인스턴스를 반환합니다. 이렇게 함으로써, 여러 개의 값을 데이터 집합으로 그룹화하는 데 도움이 됩니다.

함수의 인자 개수 줄이기

namedtuple을 사용하면 함수에 전달되는 인자의 개수를 줄일 수 있습니다. 예를 들어, 함수가 많은 인자를 사용한다면, 이를 namedtuple로 대체함으로써 코드를 더 간결하게 만들 수 있습니다.

아래의 예제는 Rectangle 클래스의 인스턴스를 사용하여 함수의 인자 개수를 줄이는 코드입니다:

from collections import namedtuple
Rectangle = namedtuple('Rectangle', ['width', 'height'])
def calculate_area(rectangle):
return rectangle.width * rectangle.height
my_rectangle = Rectangle(10, 20)
area = calculate_area(my_rectangle)
print(area) # 200

위의 예제에서 Rectangle 클래스의 인스턴스를 생성하고, 이를 calculate_area() 함수에 인자로 전달하였습니다. 이렇게 함으로써, 함수에 전달되는 인자의 개수를 줄이고 코드를 더 가독성 높게 만들었습니다.

파일과 데이터베이스로부터 탭으로 구분된 데이터 읽기

namedtuple을 사용하여 탭으로 구분된 데이터를 파일이나 데이터베이스로부터 읽을 수 있습니다. 이렇게 하면 데이터를 쉽게 파싱하고 필드에 액세스할 수 있습니다.

아래의 예제는 Person 클래스의 인스턴스를 생성하고, 파일로부터 데이터를 읽어오는 코드입니다:

from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'gender'])
def read_people_data(file_path):
people = []
with open(file_path, 'r') as file:
file.readline() # Skip header line
for line in file:
name, age, gender = line.strip().split('\t')
person = Person(name, int(age), gender)
people.append(person)
return people
people_data = read_people_data('data.txt')
for person in people_data:
print(f'Name: {person.name}, Age: {person.age}, Gender: {person.gender}')

위의 예제에서 read_people_data() 함수는 파일에서 데이터를 읽어와 Person 클래스의 인스턴스를 생성합니다. 그리고 각각의 인스턴스를 people 리스트에 추가합니다.

이렇게 namedtuple을 사용하면 데이터 파싱 작업과 필드 접근을 쉽게 수행할 수 있습니다.

namedtuple vs 다른 데이터 구조 사용하기

namedtuple은 효율적인 데이터 구조인데, 이에는 몇 가지 유사한 데이터 구조들과 비교하여 어떤 상황에서 사용하는 것이 가장 적합한지 알아보는 것이 좋습니다.

namedtuple vs 사전

namedtuple과 사전은 필드 이름과 값을 연결시켜 데이터를 저장하는 데에 유용한 데이터 구조입니다. 하지만 사전은 수정 가능(mutable)하므로, 데이터가 불변(immutable)해야 하는 경우에는 namedtuple을 사용하는 것이 더 안전합니다.

또한, namedtuple은 속성에 접근할 때 .을 사용하여 필드 이름으로 액세스할 수 있으므로, 코드의 가독성을 향상시킵니다. 반면에 사전은 키를 사용하여 값을 가져와야 하므로, 이해하기 어려울 수 있습니다.

namedtuple vs 데이터 클래스

namedtuple과 데이터 클래스는 모두 데이터를 나타내기 위한 구조체를 생성하는 데 사용됩니다. 두 가지 구조체 모두 필드 이름과 값을 연결시켜 데이터를 저장합니다. 하지만 데이터 클래스는 namedtuple의 몇 가지 기능을 확장한 형태라고 볼 수 있습니다.

데이터 클래스는 클래스를 정의하고, 데이터를 파싱 및 검증하거나 추가적인 메서드를 정의하는 데 훨씬 유연성이 있습니다. 따라서 데이터 클래스는 데이터에 추가적인 동작을 제공해야 할 때 더 적합한 선택입니다.

namedtuple vs typing.NamedTuple

namedtupletyping.NamedTuple은 모두 필드 이름을 사용하여 값을 액세스할 수 있는 데이터 구조를 생성하는 데 사용됩니다. 둘의 차이점은 typing.NamedTuple을 사용한 코드가 타입 힌트(type hint)를 지원한다는 것입니다.

typing.NamedTuple을 사용하면 필드의 타입을 정의할 수 있어 코드의 가독성을 향상시킵니다. 또한, IDE나 정적 타입 검사기와 같은 도구를 사용하여 타입 에러를 미리 찾을 수도 있습니다. 따라서 타입 힌트가 중요한 경우에는 typing.NamedTuple을 사용하는 것이 좋습니다.

namedtuple 클래스 서브클래싱하기

namedtuple은 서브클래스를 만들어 추가적인 기능을 제공하는 데 사용할 수도 있습니다. 이렇게 함으로써 namedtuple이 가지고 있는 기능을 확장하거나 수정할 수 있습니다.

서브클래스는 기존 namedtuple 클래스를 상속받아 새로운 필드나 메서드를 추가하는 것으로 정의됩니다. 이를 통해 필요한 기능을 직접 구현할 수 있으며, 코드의 재사용성 및 유지보수성을 높일 수 있습니다.

아래의 예제는 Person 클래스를 상속받아 Employee 클래스를 정의하는 코드입니다:

from collections import namedtuple
Person = namedtuple('Person', ['name', 'age'])
class Employee(Person):
def __init__(self, name, age, id):
super().__init__(name, age)
self.id = id
def get_employee_info(self):
return f'Name: {self.name}, Age: {self.age}, ID: {self.id}'
employee = Employee('Alice', 25, 12345)
print(employee.get_employee_info()) # Name: Alice, Age: 25, ID: 12345

위의 예제에서 Employee 클래스는 Person 클래스를 상속받았습니다. Employee 클래스는 get_employee_info() 메서드를 추가로 구현하였습니다. 이렇게 하면 Employee 클래스의 인스턴스는 Person 클래스의 기능과 함께 추가된 기능을 사용할 수 있습니다.

튜플 vs namedtuple의 생성 시간 측정하기

namedtuple은 튜플과 마찬가지로 속도가 빠르며, 메모리를 효율적으로 사용한다는 장점이 있습니다. 이러한 이유로, namedtuple은 모든 상황에서 더 좋은 성능을 보장하지는 않습니다.

아래의 예제는 튜플과 namedtuple의 생성 시간을 비교하는 코드입니다:

from collections import namedtuple
import time
# 튜플 생성 시간 측정
start_time = time.time()
for _ in range(1000000):
person = ('Alice', 25, 'Female')
end_time = time.time()
elapsed_time = end_time - start_time
print(f'튜플 생성 시간: {elapsed_time}초')
# namedtuple 생성 시간 측정
start_time = time.time()
Person = namedtuple('Person', ['name', 'age', 'gender'])
for _ in range(1000000):
person = Person('Alice', 25, 'Female')
end_time = time.time()
elapsed_time = end_time - start_time
print(f'namedtuple 생성 시간: {elapsed_time}초')

위의 예제에서 time 모듈을 사용하여 각각의 생성 시간을 측정합니다. for 루프에서 1000000번의 반복을 수행하며, 튜플과 namedtuple을 생성합니다.

실행 결과를 보면, namedtuple을 사용한 코드가 튜플을 사용한 코드보다 더 짧은 시간이 걸린 것을 확인할 수 있습니다. 하지만 실제로 코드의 성능을 개선하고자 할 때는, 특정 상황에서의 성능 향상을 확인하는 것이 중요합니다.

결론

namedtuple을 사용하면, 필드 이름으로 데이터에 액세스할 수 있는 튜플과 유사한 클래스를 생성할 수 있습니다. namedtuple을 사용하여 Pythonic 코드를 작성하고, 코드의 가독성과 유지보수성을 향상시킬 수 있습니다.

이 튜토리얼에서는 namedtuple 클래스를 생성하는 방법과 몇 가지 추가 기능에 대해 배웠습니다. 또한, namedtuple과 다른 데이터 구조들을 비교하고, 서브클래싱하여 추가 기능을 제공하는 방법에 대해 알아보았습니다. 마지막으로, 튜플과 namedtuple의 성능을 비교하였습니다.

namedtuple은 선택적 인자를 사용하거나, 데이터 파싱 작업을 쉽게 수행하며, 함수의 인자 개수를 줄이는 등의 다양한 장점을 제공합니다. 따라서 namedtuple을 사용하여 코드를 작성할 때, 더 깔끔하고 Pythonic하게 코드를 작성할 수 있습니다.