Що таке "названі кортежі" в Python?


906

Читаючи зміни в Python 3.1 , я знайшов щось ... несподіване:

Тепер кортеж sys.version_info тепер називається кортежем :

Я ніколи не чув про названі кортежі раніше, і думав, що елементи можна або проіндексувати цифрами (як у кортежах і списках), або клавішами (як у диктах). Я ніколи не очікував, що вони можуть індексуватися обома способами.

Таким чином, мої запитання:

  • Як називаються кортежі?
  • Як ними користуватися?
  • Чому / коли слід використовувати названі кортежі замість звичайних кортежів?
  • Чому / коли слід використовувати звичайні кортежі замість названих кортежів?
  • Чи є якийсь "названий список" (змінна версія названого кортежу)?

Відповіді:


1196

Названі кортежі - це в основному легкі для створення легкі типи об’єктів. Названі екземпляри кортежу можна посилатись за допомогою об'єктоподібної змінної перенаправлення або стандартного синтаксису кортежу. Вони можуть використовуватися аналогічно structчи іншим типовим записам, за винятком того, що вони незмінні. Вони були додані в Python 2.6 та Python 3.0, хоча є рецепт реалізації в Python 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

Таким чином, ви повинні використовувати названі кортежі замість кортежів у будь-якому місці, на який ви думаєте, що позначення об'єкта зробить ваш код більш пітонічним і легше читабельним . Я особисто почав використовувати їх для представлення дуже простих типів значень, особливо при передачі їх як параметрів функції. Це робить функції більш читабельними, не бачачи контексту упаковки кортежу.

Крім того, ви також можете замінити звичайні незмінні класи, які не мають функцій , лише поля з ними. Ви навіть можете використовувати названі типи кортезів як базові класи:

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

Я не знаю жодної форми "списку з назвою", яка дозволяє вам додавати нові поля. Ви можете просто захотіти використовувати словник у цій ситуації. Названі кортежі можуть бути перетворені в словники, за допомогою pt1._asdict()яких повертається, {'x': 1.0, 'y': 5.0}і ними можна керувати за допомогою всіх звичайних функцій словника.

Як уже зазначалося, ви повинні перевірити документацію для отримання додаткової інформації, з якої були побудовані ці приклади.


35
від python 3.7, також розглядають класи класів даних як альтернативу (можливий зворотний порт для 3.6, але не більш ранніх версій)
innov8

3
Якщо вам потрібен змінний тип запису - використовуйте простий клас із визначеним__slots__
madzohan

яка основна причина використання класів даних rcdtype not data
Voyager

Альтернатива Dict це словник атрибут stackoverflow.com/questions/4984647 / ...
mrgloom

Оскільки ця відповідь ви завжди знайдете, можливо, варто згадати, що зараз існує також такий варіант, typing.NamedTupleякий дозволяє вводити підказки типу і особливо зручний для підкласифікації.
DerWeh

101

namedtuple - це фабрична функція створення кладовища кортежу. За допомогою цього класу ми також можемо створити кортежі, які також можна називати по імені.

import collections

#Create a namedtuple class with names "a" "b" "c"
Row = collections.namedtuple("Row", ["a", "b", "c"], verbose=False, rename=False)   

row = Row(a=1,b=2,c=3) #Make a namedtuple from the Row class we created

print row    #Prints: Row(a=1, b=2, c=3)
print row.a  #Prints: 1
print row[0] #Prints: 1

row = Row._make([2, 3, 4]) #Make a namedtuple from a list of values

print row   #Prints: Row(a=2, b=3, c=4)

5
Параметри багатослівного перейменування та перейменування за замовчуванням встановлені за замовчуванням, тому їх не потрібно чітко встановлювати на це значення.
Трисмегістос

namedtuple is a factory function for making a tuple class.це, мабуть, єдина правильна відповідь тут: P
Mr_and_Mrs_D

90

Як називаються кортежі?

Названий кортеж - кортеж.

Це робить усе, що може кортеж.

Але це більше, ніж просто кортеж.

Це специфічний підклас кортежу, програмно створений відповідно до вашої специфікації, із названими полями та фіксованою довжиною.

Наприклад, це створює підклас кортежу, окрім того, що має фіксовану довжину (у цьому випадку три), він може бути використаний скрізь, коли кортеж використовується без розриву. Це відома як заміна Ліскова.

Нове в Python 3.6 , ми можемо використовувати визначення класу,typing.NamedTupleщоб створити nametuple:

from typing import NamedTuple

class ANamedTuple(NamedTuple):
    """a docstring"""
    foo: int
    bar: str
    baz: list

Вищенаведене - те саме, що наведено нижче, за винятком того, що вище вказані додаткові анотації та докстринг Нижче наведено в Python 2+:

>>> 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'

Названі кортежі - кортежі, які дозволяють отримати доступ до їх елементів по імені, а не просто індексувати!

Ви робите найменування таким чином:

>>> 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це в основному класи, які ви можете створити за допомогою легкої скорочення. Ставтесь до них як до занять. Визначте їх на рівні модуля, щоб соління та інші користувачі могли їх знайти.

Робочий приклад на рівні глобального модуля:

>>> 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)

Чому / коли слід використовувати звичайні кортежі замість названих кортежів?

Можливо, було б регресією перейти від використання названих кортежів до кортежів. Попереднє дизайнерське рішення орієнтується на те, чи варто вартість додаткового коду, що стосується покращення читабельності, коли використовується кортеж.

Немає додаткової пам'яті, яка використовується названими кортежами порівняно з кортежами.

Чи є якийсь "названий список" (змінна версія названого кортежу)?

Ви шукаєте або прорізний об'єкт, який реалізує всю функціональність списку статичного розміру, або підкласового списку, який працює як названий кортеж (і який-то блокує список не змінюватися в розмірах.)

А тепер розширений і, можливо, навіть Лісков замінний, приклад першого:

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__:

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

44

namedtuples - відмінна особливість, вони є ідеальним контейнером для даних. Коли вам доведеться "зберігати" дані, ви використовуєте кортежі або словники, наприклад:

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

або:

user = ("John", 20)

Словниковий підхід є надзвичайним, оскільки диктанти змінюються і повільніше, ніж кортежі. З іншого боку, кортежі незмінні та легкі, але не мають читабельності для великої кількості записів у полях даних.

Названі парни є ідеальним компромісом для двох підходів, мають велику читабельність, легкість і незмінність (плюс вони поліморфні!).


9
Майте на увазі, що nametuples набагато повільніше, ніж дикти, якщо ви отримуєте доступ до їх атрибутів по імені: ntuple.fooпроти ntuple[1]останнього набагато швидше. Детальніше про це: stackoverflow.com/questions/2646157 / ...
Rotareti

28

названі кортежі дозволяють зворотну сумісність з кодом, який перевіряє наявність такої версії

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

при цьому дозволяючи майбутньому коду бути більш чітким, використовуючи цей синтаксис

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

12

найменування

- це один із найпростіших способів очистити свій код і зробити його більш читабельним. Він самостійно документує те, що відбувається в кортежі. Екземпляри названих наборів настільки ж ефективні в пам'яті, як і звичайні кортежі, оскільки у них немає словників для окремих примірників, що робить їх швидшими, ніж словники.

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"

Так важче зрозуміти, що відбувається на першому прикладі. З ім’ям nametuple кожне поле має ім'я. І ви отримуєте доступ до нього по імені, а не по позиції чи індексу. Замість цього p[1]ми можемо назвати це p.saturation. Це легше зрозуміти. І виглядає чистіше.

Створити екземпляр namedtuple простіше, ніж створити словник.

# 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

Коли ви можете використовувати nametuple

  1. Як тільки було сказано, названий набір полегшує розуміння кортежів набагато простіше. Тож якщо вам потрібно посилатись на елементи в кортежі, то створювати їх як названіпари просто має сенс.
  2. Окрім того, що більш легкий, ніж словник, namedtuple також забезпечує порядок на відміну від словника.
  3. Як у наведеному вище прикладі, простіше створити екземпляр namedtuple, ніж словник. І посилання на елемент у названому кортежі виглядає чистіше, ніж у словнику. p.hueа не p['hue'].

Синтаксис

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
  • namedtuple знаходиться в бібліотеці колекцій.
  • typename: Це ім'я нового підкласу кортежів.
  • field_names: Послідовність імен для кожного поля. Це може бути послідовність, як у списку ['x', 'y', 'z']або рядку x y z(без коми, просто пробіли) або x, y, z.
  • Перейменувати: Якщо перейменувати True, недійсні імена полів автоматично замінюються на імена позицій. Наприклад, ['abc', 'def', 'ghi','abc']перетворюється на ['abc', '_1', 'ghi', '_3'], виключаючи ключове слово 'def'(оскільки це зарезервоване слово для визначення функцій) та дублікат імені поля 'abc'.
  • багатослівна: Якщо дієслівна True, визначення класу друкується безпосередньо перед побудовою.

Ви все ще можете отримати доступ до nametuples за їх місцем, якщо ви захочете. p[1] == p.saturation. Він досі розпаковується, як звичайний кортеж.

Методи

Всі регулярні кортежні методи підтримуються. Наприклад: min (), max (), len (), in, not in, concatenation (+), index, slice тощо. І є кілька додаткових для nametuple. Примітка: все це починається з підкреслення. _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Виробляє newекземпляр; він не змінює оригінал або не замінює старе значення. Звичайно, ви можете зберегти новий результат у змінній.p = p._replace(hue=169)

_make

Створює новий екземпляр із існуючої послідовності або ітерабельним.

Синтаксис

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

Повертає новий OrdersDict, який відображає назви полів у відповідні їм значення.

Синтаксис

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


Зауважте, що відповідно до PEP8 окремий підкреслення вважається "слабким показником" внутрішнього використання " зі своєю поведінкою. Обережно при використанні функцій, які починаються з _!
Єнс

8

Що називаєтьсяtuple?

Як випливає з назви, nametuple - це кортеж з назвою. У стандартному кортежі ми отримуємо доступ до елементів за допомогою індексу, тоді як namedtuple дозволяє користувачеві визначати ім’я для елементів. Це дуже зручно, особливо для обробки файлів csv (значення, розділених комами) та роботи зі складним і великим набором даних, де код стає безладним із використанням індексів (не настільки пітонічних).

Як ними користуватися?

>>>from collections import namedtuple
>>>saleRecord = namedtuple('saleRecord','shopId saleDate salesAmout totalCustomers')
>>>
>>>
>>>#Assign values to a named tuple 
>>>shop11=saleRecord(11,'2015-01-01',2300,150) 
>>>shop12=saleRecord(shopId=22,saleDate="2015-01-01",saleAmout=1512,totalCustomers=125)

Читання

>>>#Reading as a namedtuple
>>>print("Shop Id =",shop12.shopId)
12
>>>print("Sale Date=",shop12.saleDate)
2015-01-01
>>>print("Sales Amount =",shop12.salesAmount)
1512
>>>print("Total Customers =",shop12.totalCustomers)
125

Цікавий сценарій обробки CSV:

from csv import reader
from collections import namedtuple

saleRecord = namedtuple('saleRecord','shopId saleDate totalSales totalCustomers')
fileHandle = open("salesRecord.csv","r")
csvFieldsList=csv.reader(fileHandle)
for fieldsList in csvFieldsList:
    shopRec = saleRecord._make(fieldsList)
    overAllSales += shopRec.totalSales;

print("Total Sales of The Retail Chain =",overAllSales)

5

У Python всередині є гарне використання контейнера під назвою названий кортеж, він може бути використаний для створення визначення класу і має всі особливості оригінального кортежу.

Використання названого кортежу буде безпосередньо застосовано до шаблону класу за замовчуванням для створення простого класу, цей метод дозволяє багато коду для поліпшення читабельності, а також дуже зручно при визначенні класу.


2

Інший спосіб (новий спосіб) для використання названого кортежу - це використання NamedTuple від набору пакету: Введіть підказки в namedtuple

Давайте скористаємося прикладом основної відповіді в цій публікації, щоб побачити, як її використовувати.

(1) Перед використанням названого кортежу код виглядає так:

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)
print(line_length)

(2) Тепер ми використовуємо названий кортеж

from typing import NamedTuple, Number

успадкуйте клас NamedTuple та визначте ім'я змінної в новому класі. test - це назва класу.

class test(NamedTuple):
x: Number
y: Number

створити екземпляри з класу та призначити їм значення

pt1 = test(1.0, 5.0)   # x is 1.0, and y is 5.0. The order matters
pt2 = test(2.5, 1.5)

використовувати змінні з екземплярів для обчислення

line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)
print(line_length)

1

Спробуйте це:

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

-1

Всі інші вже відповіли на це, але я думаю, що я ще маю щось додати.

Namedtuple можна інтуїтивно розглядати як ярлик для визначення класу.

Дивіться громіздкий і звичайний спосіб визначення а class.

class Duck:
    def __init__(self, color, weight):
        self.color = color
        self.weight = weight
red_duck = Duck('red', '10')

    In [50]: red_duck
    Out[50]: <__main__.Duck at 0x1068e4e10>
    In [51]: red_duck.color
    Out[51]: 'red'

Як для namedtuple

from collections import namedtuple
Duck = namedtuple('Duck', ['color', 'weight'])
red_duck = Duck('red', '10')

In [54]: red_duck
Out[54]: Duck(color='red', weight='10')
In [55]: red_duck.color
Out[55]: 'red'

2
Вибачте, але це неправильно. Названий кортеж також підтримує такі: red_duck[0]або len(red_duck)або for x in red_duck: print(x). Крім того, названі кортежі незмінні, тому ці операції не вдасться: red_duck[0] = 2, red_duck.foo = 'bar'. Оскільки вони незмінні, названі кортежі можуть використовуватися як dictключі.
Denilson Sá Maia

Так, це основи.
Обчислення

1
@JawSaw Ні, це не "основи". Названі кортежі підтримують абсолютно інший набір функціоналу, ніж звичайні заняття. Хоча по суті названі кортежі є класом, це не означає, що класи називаються кортежами.
Підключіть свій зарядний пристрій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.