Tuples adı nedir?
Adlandırılmış bir demet bir demettir.
Bir demetin yapabileceği her şeyi yapar.
Ama bu sadece bir demetten daha fazlası.
Adlandırılmış alanlar ve sabit bir uzunluk ile, belirtiminize göre programlı olarak oluşturulan bir demetin belirli bir alt sınıfıdır.
Bu, örneğin, bir tuple alt sınıfı oluşturur ve sabit uzunlukta (bu durumda üç) olmanın yanı sıra, bir tupleın kırılmadan kullanıldığı her yerde kullanılabilir. Bu Liskov'un ikame edilebilirliği olarak bilinir.
Python 3.6'da yeni olan , adlandırılmış bir gruptyping.NamedTuple
oluşturmak içinile bir sınıf tanımı kullanabiliriz:
from typing import NamedTuple
class ANamedTuple(NamedTuple):
"""a docstring"""
foo: int
bar: str
baz: list
Yukarıdakiler, aşağıdakilerle aynıdır, ancak yukarıdakiler ayrıca tip ek açıklamalarına ve bir doktora işaretine sahiptir. Aşağıdakiler Python 2+ sürümünde mevcuttur:
>>> from collections import namedtuple
>>> class_name = 'ANamedTuple'
>>> fields = 'foo bar baz'
>>> ANamedTuple = namedtuple(class_name, fields)
Bu onu başlatır:
>>> ant = ANamedTuple(1, 'bar', [])
İnceleyebilir ve özelliklerini kullanabiliriz:
>>> ant
ANamedTuple(foo=1, bar='bar', baz=[])
>>> ant.foo
1
>>> ant.bar
'bar'
>>> ant.baz.append('anything')
>>> ant.baz
['anything']
Daha derin açıklama
Adlandırılmış tuples'i anlamak için önce bir tupleın ne olduğunu bilmeniz gerekir. Bir demet aslında değişmezdir (bellekte yerinde değiştirilemez) listesidir.
Düzenli bir demet nasıl kullanabilirsiniz:
>>> student_tuple = 'Lisa', 'Simpson', 'A'
>>> student_tuple
('Lisa', 'Simpson', 'A')
>>> student_tuple[0]
'Lisa'
>>> student_tuple[1]
'Simpson'
>>> student_tuple[2]
'A'
Bir tuple'i yinelenebilir ambalajı açarak genişletebilirsiniz:
>>> first, last, grade = student_tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
Adlandırılmış tuples, öğelerine sadece dizin yerine adla erişilmesine izin veren tuples!
Bunun gibi adlandırılmış bir grup yaparsınız:
>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])
Ayrıca adların boşluklarla ayrılmış tek bir dize, API'nın biraz daha okunabilir bir kullanımı da kullanabilirsiniz:
>>> Student = namedtuple('Student', 'first last grade')
Nasıl kullanılır?
Tuples'in yapabileceği her şeyi yapabilir (yukarıya bakın) ve aşağıdakileri yapabilirsiniz:
>>> 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')
Bir yorumcu sordu:
Büyük bir komut dosyasında veya programda, genellikle adlandırılmış bir grup nerede tanımlanır?
Birlikte oluşturduğunuz türler namedtuple
temel olarak kolay steno ile oluşturabileceğiniz sınıflardır. Onlara sınıf gibi davran. Bunları modül düzeyinde tanımlayın, böylece turşu ve diğer kullanıcılar onları bulabilir.
Global modül seviyesinde çalışma örneği:
>>> 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')
Bu da tanımın aranmamasını gösterir:
>>> 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
Normal tuples yerine neden / ne zaman adlandırılmış tuples kullanmalıyım?
Kodunuzda tuple elemanlarının semantiğinin ifade edilmesi için kodunuzu geliştirdiğinde kullanın.
Değişmeyen veri özniteliklerine sahip ve herhangi bir işlevsellik içermeyen bir nesne kullanırsanız, bunları nesne yerine kullanabilirsiniz.
İşlev eklemek için bunları alt sınıflara ayırabilirsiniz , örneğin :
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)
Neden / ne zaman adlandırılmış tuples yerine normal tuples kullanmalıyım?
Muhtemelen adlandırılmış tuples kullanmaktan tuples'a geçmek bir gerileme olacaktır. Açık tasarım kararı, söz konusu ekstra koddan gelen maliyetin, demet kullanıldığında daha iyi okunabilirliğe değip değmeyeceği etrafında odaklanmaktadır.
Adlandırılmış tuples tarafından tuples'e karşı kullanılan fazladan bellek yoktur.
Herhangi bir "adlandırılmış liste" var mı (adlandırılmış grubun değiştirilebilir bir sürümü)?
Statik olarak boyutlandırılmış bir listenin tüm işlevlerini uygulayan oluklu bir nesne veya adlandırılmış bir grup gibi çalışan alt sınıflı bir liste mi arıyorsunuz (ve bir şekilde listenin boyutunun değişmesini engeller).
Şimdi genişletilmiş ve hatta belki de Liskov'un yerine geçebilen bir örnek:
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__)
Ve kullanmak için, sadece alt sınıf ve tanımlayın __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