Apa yang disebut tuple?
Sebuah tuple bernama adalah tuple.
Itu melakukan semua yang bisa dilakukan oleh tuple.
Tapi itu lebih dari sekadar tuple.
Ini adalah subkelas spesifik dari tupel yang secara pemrograman dibuat sesuai spesifikasi Anda, dengan bidang bernama dan panjang tetap.
Ini, misalnya, membuat subkelas tupel, dan selain memiliki panjang tetap (dalam hal ini, tiga), ia dapat digunakan di mana pun tupel digunakan tanpa putus. Ini dikenal sebagai substitusi Liskov.
Baru di Python 3.6 , kita bisa menggunakan definisi kelas dengantyping.NamedTuple
untuk membuat nameserupup:
from typing import NamedTuple
class ANamedTuple(NamedTuple):
"""a docstring"""
foo: int
bar: str
baz: list
Di atas sama dengan yang di bawah, kecuali yang di atas juga memiliki jenis anotasi dan dokumentasi. Di bawah ini tersedia dalam Python 2+:
>>> from collections import namedtuple
>>> class_name = 'ANamedTuple'
>>> fields = 'foo bar baz'
>>> ANamedTuple = namedtuple(class_name, fields)
Ini instantiate itu:
>>> ant = ANamedTuple(1, 'bar', [])
Kami dapat memeriksanya dan menggunakan atributnya:
>>> ant
ANamedTuple(foo=1, bar='bar', baz=[])
>>> ant.foo
1
>>> ant.bar
'bar'
>>> ant.baz.append('anything')
>>> ant.baz
['anything']
Penjelasan lebih dalam
Untuk memahami tupel bernama, Anda harus terlebih dahulu tahu apa tupel itu. Sebuah tuple pada dasarnya adalah daftar yang tidak dapat diubah (tidak dapat diubah di tempat dalam memori).
Inilah cara Anda menggunakan tuple biasa:
>>> student_tuple = 'Lisa', 'Simpson', 'A'
>>> student_tuple
('Lisa', 'Simpson', 'A')
>>> student_tuple[0]
'Lisa'
>>> student_tuple[1]
'Simpson'
>>> student_tuple[2]
'A'
Anda dapat memperluas tuple dengan membongkar iterable:
>>> first, last, grade = student_tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
Named tuple adalah tuple yang memungkinkan elemen-elemennya diakses dengan nama alih-alih hanya indeks!
Anda membuat nama bernama seperti ini:
>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])
Anda juga dapat menggunakan string tunggal dengan nama yang dipisahkan oleh spasi, penggunaan API yang sedikit lebih mudah dibaca:
>>> Student = namedtuple('Student', 'first last grade')
Bagaimana cara menggunakannya?
Anda dapat melakukan semua hal yang dapat dilakukan oleh tuple (lihat di atas) dan juga melakukan hal berikut:
>>> 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')
Seorang komentator bertanya:
Dalam skrip atau program besar, di mana biasanya orang mendefinisikan tuple bernama?
Jenis yang Anda buat namedtuple
pada dasarnya adalah kelas yang dapat Anda buat dengan singkatan yang mudah. Perlakukan mereka seperti kelas. Tentukan mereka di tingkat modul, sehingga acar dan pengguna lain dapat menemukannya.
Contoh kerja, pada tingkat modul global:
>>> 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')
Dan ini menunjukkan kegagalan untuk mencari definisi:
>>> 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
Mengapa / kapan saya harus menggunakan nama tuple alih-alih tuple normal?
Gunakan mereka ketika meningkatkan kode Anda untuk memiliki semantik elemen tuple yang dinyatakan dalam kode Anda.
Anda dapat menggunakannya sebagai ganti objek jika Anda akan menggunakan objek dengan atribut data yang tidak berubah dan tidak ada fungsi.
Anda juga dapat mensubklasifikasikan mereka untuk menambahkan fungsionalitas, misalnya :
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)
Mengapa / kapan saya harus menggunakan tuple biasa dan bukan tuple bernama?
Mungkin akan menjadi regresi untuk beralih dari menggunakan nama tupel ke tupel. Keputusan desain dimuka berpusat di sekitar apakah biaya dari kode tambahan yang terlibat layak dibaca lebih baik ketika tuple digunakan.
Tidak ada memori tambahan yang digunakan oleh nama tuple versus tuple.
Apakah ada jenis "daftar nama" (versi yang dapat diubah dari tuple bernama)?
Anda sedang mencari objek yang ditempatkan yang mengimplementasikan semua fungsi dari daftar berukuran statis atau daftar subkelas yang bekerja seperti tuple bernama (dan yang entah bagaimana memblokir daftar dari perubahan ukuran.)
A sekarang diperluas, dan mungkin bahkan Liskov yang dapat diganti, contoh yang pertama:
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__)
Dan untuk digunakan, cukup subkelas dan tentukan __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