python2 - 파이썬 namedtuple




파이썬에서 "명명 된 튜플"이란 무엇입니까? (7)

파이썬 3.1 에서 변경된 내용을 읽었을 때 , 나는 뭔가를 발견했다 ... 예상치 못한 :

sys.version_info 튜플은 이제 명명 된 튜플입니다 .

이전에 명명 된 튜플에 대해서는 들어 본 적이 없었으며, 요소는 숫자 (튜플 및 목록과 같은) 또는 키 (예 : dicts와 같은)로 인덱싱 될 수 있다고 생각했습니다. 나는 두 가지 방법으로 색인을 생성 할 수있을 것이라고 기대하지 못했습니다.

따라서 내 질문은 다음과 같습니다.

  • 명명 된 튜플이란 무엇입니까?
  • 어떻게 사용합니까?
  • 왜 / 언제 일반 튜플 대신 명명 된 튜플을 사용해야합니까?
  • 왜 이름 붙은 튜플 대신에 정규 튜플을 사용해야합니까?
  • 어떤 종류의 "명명 된 목록"(명명 된 튜플의 변형 버전)이 있습니까?

명명 된 튜플이란 무엇입니까?

명명 된 튜플은 튜플입니다.

그것은 튜플이 할 수있는 모든 것을합니다.

그러나 그것은 단순한 튜플 이상입니다.

이름 붙여진 필드와 고정 된 길이를 사용하여 프로그래밍 방식으로 생성 된 튜플의 특정 하위 클래스입니다.

예를 들어, 이것은 튜플의 서브 클래스를 생성하고 고정 된 길이 (이 경우 3 개)를 제외하고 터플이 깨지지 않고 사용되는 모든 곳에서 사용될 수 있습니다. 이것은 Liskov 대체 성으로 알려져 있습니다.

>>> from collections import namedtuple
>>> class_name = 'ANamedTuple'
>>> fields = 'foo bar baz'
>>> ANamedTuple = namedtuple(class_name, fields)

이렇게하면 다음과 같이 인스턴스화됩니다.

>>> ant = ANamedTuple(1, 'bar', [])

우리는 그것을 검사하고 속성을 사용할 수 있습니다 :

>>> ant
ANamedTuple(foo=1, bar='bar', baz=[])
>>> ant.foo
1
>>> ant.bar
'bar'
>>> ant.baz.append('anything')
>>> ant.baz
['anything']

더 깊은 설명

명명 된 튜플을 이해하려면 먼저 튜플이 무엇인지 알아야합니다. 튜플은 본질적으로 변경 불가능한 (메모리에서 내부적으로 변경할 수 없음) 목록입니다.

다음은 정규 튜플을 사용하는 방법입니다.

>>> student_tuple = 'Lisa', 'Simpson', 'A'
>>> student_tuple
('Lisa', 'Simpson', 'A')
>>> student_tuple[0]
'Lisa'
>>> student_tuple[1]
'Simpson'
>>> student_tuple[2]
'A'

반복 가능한 언 패킹을 사용하여 튜플을 확장 할 수 있습니다.

>>> first, last, grade = student_tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'

명명 된 튜플은 단지 인덱스 대신 이름으로 요소를 액세스 할 수있는 튜플입니다!

다음과 같이 namedtuple을 만든다.

>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])

공백으로 구분 된 이름을 가진 단일 문자열을 사용할 수도 있습니다. API를 약간 더 읽기 쉽게 사용할 수 있습니다.

>>> Student = namedtuple('Student', 'first last grade')

어떻게 사용합니까?

튜플이 할 수있는 모든 작업을 수행 할 수 있으며 (위 참조) 다음을 수행 할 수 있습니다.

>>> named_student_tuple = Student('Lisa', 'Simpson', 'A')
>>> named_student_tuple.first
'Lisa'
>>> named_student_tuple.last
'Simpson'
>>> named_student_tuple.grade
'A'
>>> named_student_tuple._asdict()
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> vars(named_student_tuple)
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> new_named_student_tuple = named_student_tuple._replace(first='Bart', grade='C')
>>> new_named_student_tuple
Student(first='Bart', last='Simpson', grade='C')

댓글 작성자가 물었습니다.

대형 스크립트 나 프로그램에서 일반적으로 명명 된 튜플은 어디에 정의됩니까?

namedtuple 로 생성하는 유형은 기본적으로 쉬운 속기로 작성할 수있는 클래스입니다. 그들을 수업처럼 대하십시오. pickle과 다른 사용자가 찾을 수 있도록 모듈 수준에서 정의하십시오.

전역 모듈 수준에서 작동하는 예제는 다음과 같습니다.

>>> from collections import namedtuple
>>> NT = namedtuple('NT', 'foo bar')
>>> nt = NT('foo', 'bar')
>>> import pickle
>>> pickle.loads(pickle.dumps(nt))
NT(foo='foo', bar='bar')

그리고 이것은 정의를 찾는 실패를 보여줍니다 :

>>> def foo():
...     LocalNT = namedtuple('LocalNT', 'foo bar')
...     return LocalNT('foo', 'bar')
... 
>>> pickle.loads(pickle.dumps(foo()))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <class '__main__.LocalNT'>: attribute lookup LocalNT on __main__ failed

왜 / 언제 일반 튜플 대신 명명 된 튜플을 사용해야합니까?

코드에서 튜플 요소의 의미를 표현하도록 코드를 향상시킬 때 사용하십시오. 데이터 속성이 변경되지 않고 기능이없는 객체를 사용하려는 경우 객체 대신 객체를 사용할 수 있습니다. 또한 하위 클래스를 추가하여 기능을 추가 할 수 있습니다 ( :

class Point(namedtuple('Point', 'x y')):
    """adding functionality to a named tuple"""
        __slots__ = ()
        @property
        def hypot(self):
            return (self.x ** 2 + self.y ** 2) ** 0.5
        def __str__(self):
            return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

왜 이름 붙은 튜플 대신에 정규 튜플을 사용해야합니까?

명명 된 튜플을 튜플로 바꾸는 것은 아마 회귀가 될 것입니다. 선행 디자인 결정은 튜플을 사용할 때 추가 코드의 비용이 향상된 가독성에 가치가 있는지 여부를 중심으로합니다.

명명 된 튜플 대 튜플이 사용하는 추가 메모리는 없습니다.

어떤 종류의 "명명 된 목록"(명명 된 튜플의 변형 버전)이 있습니까?

정적으로 크기가 조정 된 목록의 모든 기능을 구현하는 슬롯 된 개체 나 명명 된 튜플처럼 작동하는 하위 클래 싱 된 목록을 찾고 있습니다 (그리고 크기가 변경되지 않도록 목록이 차단됩니다).

이제 확장 된 Liskov로 대체 할 수도 있습니다.

from collections import Sequence

class MutableTuple(Sequence): 
    """Abstract Base Class for objects that work like mutable
    namedtuples. Subclass and define your named fields with 
    __slots__ and away you go.
    """
    __slots__ = ()
    def __init__(self, *args):
        for slot, arg in zip(self.__slots__, args):
            setattr(self, slot, arg)
    def __repr__(self):
        return type(self).__name__ + repr(tuple(self))
    # more direct __iter__ than Sequence's
    def __iter__(self): 
        for name in self.__slots__:
            yield getattr(self, name)
    # Sequence requires __getitem__ & __len__:
    def __getitem__(self, index):
        return getattr(self, self.__slots__[index])
    def __len__(self):
        return len(self.__slots__)

그리고 __slots__ 하위 클래스로 정의 __slots__ .

class Student(MutableTuple):
    __slots__ = 'first', 'last', 'grade' # customize 


>>> student = Student('Lisa', 'Simpson', 'A')
>>> student
Student('Lisa', 'Simpson', 'A')
>>> first, last, grade = student
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
>>> student[0]
'Lisa'
>>> student[2]
'A'
>>> len(student)
3
>>> 'Lisa' in student
True
>>> 'Bart' in student
False
>>> student.first = 'Bart'
>>> for i in student: print(i)
... 
Bart
Simpson
A

namedtuple

코드를 정리하고 더 쉽게 읽을 수있는 가장 쉬운 방법 중 하나입니다. 튜플에서 일어나는 일을 스스로 문서화합니다. Namedtuples 인스턴스는 인스턴스 별 사전이 없으므로 정규 튜플만큼 메모리가 효율적이므로 사전보다 빠릅니다.

from collections import namedtuple

Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])

 p = Color(170, 0.1, 0.6)
 if p.saturation >= 0.5:
     print "Whew, that is bright!"
 if p.luminosity >= 0.5:
     print "Wow, that is light"

튜플의 각 요소의 이름을 지정하지 않고 다음과 같이 읽습니다.

p = (170, 0.1, 0.6)
if p[1] >= 0.5:
    print "Whew, that is bright!"
if p[2]>= 0.5:
   print "Wow, that is light"

첫 번째 예에서 무엇이 진행되고 있는지 이해하는 것이 훨씬 더 어렵습니다. 명명 된 튜플로 각 필드에는 이름이 있습니다. 그리고 위치 나 색인 대신 이름으로 액세스하십시오. p[1] 대신 p.saturation이라고 부를 수 있습니다. 이해하기 쉽습니다. 그리고 그것은 더 깨끗해진다.

사전을 만드는 것보다 명명 된 튜플 인스턴스를 만드는 것이 더 쉽습니다.

# dictionary
>>>p = dict(hue = 170, saturation = 0.1, luminosity = 0.6)
>>>p['hue']
170

#nametuple
>>>from collections import namedtuple
>>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
>>>p = Color(170, 0.1, 0.6)
>>>p.hue
170

언제 namedtuple을 사용할 수 있습니까?

  1. 방금 언급 한 것처럼 명명 된 튜플을 사용하면 튜플을 훨씬 쉽게 이해할 수 있습니다. 따라서 튜플의 항목을 참조해야하는 경우 명명 된 튜플로 항목을 만드는 것이 의미가 있습니다.
  2. 사전보다 가벼운 외에 namedtuple은 사전과 달리 순서를 유지합니다.
  3. 위의 예제에서와 같이, dictionary보다 namedtuple의 인스턴스를 만드는 것이 더 간단합니다. 명명 된 튜플의 항목을 참조하는 것은 사전보다 깔끔하게 보입니다. p['hue'] 보다는 p['hue'] .

문법

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
  • namedtuple은 콜렉션 라이브러리에 있습니다.
  • typename : 이것은 새로운 튜플 하위 클래스의 이름입니다.
  • field_names : 각 필드의 일련의 이름. 리스트 ['x', 'y', 'z'] 또는 문자열 xyz (콤마, 공백없이) 또는 x, y, z 와 같은 시퀀스 일 수 있습니다.
  • rename : 이름 바꾸기가 True 이면 잘못된 필드 이름이 자동으로 위치 이름으로 바뀝니다. 예를 들어, ['abc', 'def', 'ghi','abc']['abc', '_1', 'ghi', '_3'] 로 변환되어 키워드 'def' 함수 정의를위한 예약어)와 중복 된 필드 이름 'abc' .
  • verbose : verbose가 True 이면 클래스 정의가 빌드되기 바로 전에 인쇄됩니다.

원하는 경우 이름으로 위치 튜플에 액세스 할 수 있습니다. p[1] == p.saturation . 그것은 여전히 ​​정규 튜플처럼 풀립니다.

행동 양식

모든 일반 튜플 메서드 가 지원됩니다. 예 : min (), max (), len (), in, not in, concatenation (+), index, slice 등. 그리고 namedtuple을위한 몇 가지 추가 사항이 있습니다. 참고 :이 모든 것은 밑줄로 시작합니다. _replace , _make , _asdict .

_replace 지정된 필드를 새 값으로 바꾸는 명명 된 튜플의 새 인스턴스를 리턴합니다.

문법

somenamedtuple._replace(kwargs)

>>>from collections import namedtuple

>>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
>>>p = Color(170, 0.1, 0.6)

>>>p._replace(hue=87)
Color(87, 0.1, 0.6)

>>>p._replace(hue=87, saturation=0.2)
Color(87, 0.2, 0.6)

주의 사항 : 필드 이름은 따옴표로 묶지 않습니다. 그들은 여기에 키워드입니다. 기억하십시오 : 튜플은 비록 이름이 _replace 튜플이고 _replace 메소드를 가지고 있어도 변경할 수 없습니다. _replacenew 인스턴스를 생성합니다. 원래 값을 수정하거나 이전 값을 대체하지 않습니다. 물론 새로운 결과를 변수에 저장할 수 있습니다. p = p._replace(hue=169)

_make

기존의 시퀀스 또는 iterable로부터 새로운 인스턴스를 만듭니다.

문법

somenamedtuple._make(iterable)

 >>>data = (170, 0.1, 0.6)
 >>>Color._make(data)
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make([170, 0.1, 0.6])  #the list is an iterable
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make((170, 0.1, 0.6))  #the tuple is an iterable
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make(170, 0.1, 0.6) 
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<string>", line 15, in _make
TypeError: 'float' object is not callable

마지막 사건은 어떻게 된거야? 괄호 안의 항목은 반복 가능해야합니다. 따라서 괄호 안의 목록이나 튜플은 작동하지만 반복 가능한 값으로 묶지 않은 값의 시퀀스는 오류를 반환합니다.

_asdict

필드 이름을 해당 값으로 매핑하는 새 OrderedDict 를 반환합니다.

문법

somenamedtuple._asdict()

 >>>p._asdict()
OrderedDict([('hue', 169), ('saturation', 0.1), ('luminosity', 0.6)])

참조 : https://www.reddit.com/r/Python/comments/38ee9d/intro_to_namedtuple/

명명 된 튜플과 비슷하지만 변경 가능한 https://pypi.python.org/pypi/namedlist 라는 이름의 목록도 https://pypi.python.org/pypi/namedlist


명명 된 튜플은 다음과 같은 버전을 검사하는 코드와의 하위 호환성을 허용합니다.

>>> sys.version_info[0:2]
(3, 1)

이 구문을 사용하여 향후 코드를보다 명확하게 지정할 수 있습니다.

>>> sys.version_info.major
3
>>> sys.version_info.minor
1

명명 된 튜플은 큰 특징이며, 데이터를위한 완벽한 컨테이너입니다. 데이터를 "저장"해야 할 때 튜플이나 사전을 사용할 수 있습니다 :

user = dict(name="John", age=20)

또는:

user = ("John", 20)

dict은 튜플보다 변경 가능하고 느리기 때문에 사전 접근법은 압도적입니다. 반면에 튜플은 불변이고 가볍지 만 데이터 필드의 많은 항목에 대한 가독성이 부족합니다.

명명 된 튜플은 두 가지 접근법의 완벽한 절충안입니다. 가독성, 경량 성 및 불변성 (더하기 다형성)이 있습니다.


이 시도:

collections.namedtuple()

기본적으로 namedtuples 은 가볍고 객체 유형을 쉽게 생성 할 수 있습니다. 튜플을 간단한 작업을위한 편리한 컨테이너로 변환합니다. namedtuples 된 튜플을 사용하면 튜플 멤버에 액세스 할 때 정수 인덱스를 사용할 필요가 없습니다.

예 :

코드 1 :

>>> from collections import namedtuple

>>> Point = namedtuple('Point','x,y')

>>> pt1 = Point(1,2)

>>> pt2 = Point(3,4)

>>> dot_product = ( pt1.x * pt2.x ) +( pt1.y * pt2.y )

>>> print dot_product
11

코드 2 :

>>> from collections import namedtuple

>>> Car = namedtuple('Car','Price Mileage Colour Class')

>>> xyz = Car(Price = 100000, Mileage = 30, Colour = 'Cyan', Class = 'Y')

>>> print xyz

Car(Price=100000, Mileage=30, Colour='Cyan', Class='Y')
>>> print xyz.Class
Y

파이썬 내부에는 명명 된 튜플이라는 컨테이너가 잘 사용되어 클래스의 정의를 만드는 데 사용할 수 있으며 원래 튜플의 모든 기능을 가지고 있습니다.

명명 된 튜플을 사용하면 기본 클래스 템플릿에 직접 적용되어 간단한 클래스를 생성 할 수 있습니다.이 메서드는 많은 코드로 가독성을 향상시킬 수 있으며 클래스를 정의 할 때도 매우 편리합니다.


명명 된 튜플은 기본적으로 생성하기 쉽고 가벼운 객체 유형입니다. 명명 된 튜플 인스턴스는 객체와 같은 변수 역 참조 또는 표준 튜플 구문을 사용하여 참조 할 수 있습니다. 그들은 불변이라는 점을 제외하고 struct 나 다른 공통 레코드 유형과 유사하게 사용할 수 있습니다. 파이썬 2.6과 파이썬 3.0에서 추가되었지만 파이썬 2.4에서는 구현법 이있다.

예를 들어, 점을 튜플 (x, y) 로 표현하는 것이 일반적입니다. 이로 인해 다음과 같은 코드가 생성됩니다.

pt1 = (1.0, 5.0)
pt2 = (2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)

명명 된 튜플을 사용하면 더 쉽게 읽을 수 있습니다.

from collections import namedtuple
Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)

그러나 명명 된 튜플은 여전히 ​​일반 튜플과 하위 호환되므로 다음과 같이 작동합니다.

Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
# use index referencing
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)
 # use tuple unpacking
x1, y1 = pt1

따라서, 튜플 대신에 명명 된 튜플을 사용해야한다. 객체 표기법을 사용하면 코드를 더 pythonic하고 더 쉽게 읽을 수있다 . 개인적으로 매우 단순한 값 유형을 나타 내기 위해 이들을 사용하기 시작했습니다. 특히 함수에 매개 변수로 전달할 때 그렇습니다. 튜플 패킹의 컨텍스트를 보지 않고 함수를 더 읽기 쉽게 만듭니다.

또한, 함수가없는 일반 불변 클래스를 대체 할 수 있으며 , 필드 만 사용할 수 있습니다. 명명 된 튜플 유형을 기본 클래스로 사용할 수도 있습니다.

class Point(namedtuple('Point', 'x y')):
    [...]

그러나 튜플의 경우와 마찬가지로 명명 된 튜플의 속성은 변경할 수 없습니다.

>>> Point = namedtuple('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
AttributeError: can't set attribute

값을 변경하려면 다른 유형이 필요합니다. 변경 가능한 레코드 유형 에는 새로운 값을 속성에 설정할 수있는 편리한 방법이 있습니다.

>>> from rcdtype import *
>>> Point = recordtype('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
>>> print(pt1[0])
    2.0

그러나 새로운 필드를 추가 할 수있는 "명명 된 목록"의 형태는 알지 못합니다. 이 상황에서 사전을 사용하고 싶을 수도 있습니다. 명명 된 튜플은 {'x': 1.0, 'y': 5.0} 을 반환하는 pt1._asdict() 를 사용하여 사전으로 변환 할 수 있으며 모든 일반적인 사전 기능을 사용하여 조작 할 수 있습니다.

이미 언급했듯이이 예제가 작성된 자세한 정보 는 설명서확인 해야합니다.





namedtuple