5. ساختمان داده‌ها

این فصل برخی از مواردی را که تاکنون یاد گرفته‌اید با جزئیات بیشتری توضیح می‌دهد و همچنین چند مورد جدید نیز اضافه می‌کند.

5.1. بیشتر درباره‌ی فهرست‌ها

نوع داده‌ی list چند متد دیگر نیز دارد. در اینجا تمام متدهای اشیای list آمده‌اند:

list.append(value, /)

یک آیتم را به انتهای فهرست اضافه می‌کند. مشابه a[len(a):] = [x] است.

list.extend(iterable, /)

فهرست را با افزودن تمام آیتم‌های شیء پیمایش‌پذیر گسترش می‌دهد. مشابه a[len(a):] = iterable است.

list.insert(index, value, /)

یک آیتم را در موقعیت مشخصی درج می‌کند. اولین آرگومان، اندیس عنصری است که آیتم باید پیش از آن درج شود؛ بنابراین a.insert(0, x) آیتم را در ابتدای فهرست درج می‌کند و a.insert(len(a), x) معادل a.append(x) است.

list.remove(value, /)

اولین آیتم از فهرست را که مقدار آن برابر با value است حذف می‌کند. اگر چنین آیتمی وجود نداشته باشد، یک ValueError پرتاب می‌کند.

list.pop(index=-1, /)

آیتم موجود در موقعیت مشخص‌شده از فهرست را حذف می‌کند و آن را برمی‌گرداند. اگر هیچ اندیسی مشخص نشده باشد، a.pop() آخرین آیتم فهرست را حذف کرده و برمی‌گرداند. اگر فهرست خالی باشد یا اندیس خارج از محدوده‌ی فهرست باشد، یک IndexError پرتاب می‌کند.

list.clear()

تمام آیتم‌های فهرست را حذف می‌کند. مشابه del a[:] است.

list.index(value[, start[, stop]])

اندیس مبتنی بر صفرِ اولین رخداد value در فهرست را برمی‌گرداند. اگر چنین آیتمی وجود نداشته باشد، یک ValueError پرتاب می‌کند.

آرگومان‌های اختیاری start و end مانند نمادگذاری اسلایس تفسیر می‌شوند و برای محدود کردن جست‌وجو به یک زیردنباله‌ی مشخص از فهرست استفاده می‌شوند. اندیس بازگردانده‌شده نسبت به ابتدای دنباله‌ی کامل محاسبه می‌شود، نه نسبت به آرگومان start.

list.count(value, /)

تعداد دفعاتی که value در فهرست ظاهر می‌شود را برمی‌گرداند.

list.sort(*, key=None, reverse=False)

آیتم‌های فهرست را در جای خود مرتب می‌کند (آرگومان‌ها می‌توانند برای سفارشی‌سازی مرتب‌سازی استفاده شوند؛ برای توضیح آن‌ها به sorted() مراجعه کنید).

list.reverse()

عناصر فهرست را در جای خود معکوس می‌کند.

list.copy()

یک کپی سطحی از فهرست را برمی‌گرداند. مشابه a[:] است.

مثالی که از بیشتر متدهای فهرست استفاده می‌کند:

>>> fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
>>> fruits.count('apple')
2
>>> fruits.count('tangerine')
0
>>> fruits.index('banana')
3
>>> fruits.index('banana', 4)  # Find next banana starting at position 4
6
>>> fruits.reverse()
>>> fruits
['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange']
>>> fruits.append('grape')
>>> fruits
['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange', 'grape']
>>> fruits.sort()
>>> fruits
['apple', 'apple', 'banana', 'banana', 'grape', 'kiwi', 'orange', 'pear']
>>> fruits.pop()
'pear'

ممکن است متوجه شده باشید که متدهایی مانند insert، remove یا sort که فقط فهرست را تغییر می‌دهند، هیچ مقدار بازگشتی چاپ‌شده‌ای ندارند -- آن‌ها مقدار پیش‌فرض None را برمی‌گردانند. [1] این یک اصل طراحی برای تمام ساختارهای داده‌ی تغییرپذیر در پایتون است.

چیز دیگری که ممکن است متوجه شوید این است که همه‌ی داده‌ها قابل مرتب‌سازی یا مقایسه نیستند. برای مثال، [None, 'hello', 10] مرتب نمی‌شود، زیرا اعداد صحیح را نمی‌توان با رشته‌ها مقایسه کرد و None نیز با نوع‌های دیگر قابل مقایسه نیست. همچنین برخی نوع‌ها وجود دارند که رابطه‌ی ترتیب تعریف‌شده‌ای ندارند. برای مثال، مقایسه‌ی 3+4j < 5+7j معتبر نیست.

5.1.1. استفاده از فهرست‌ها به‌عنوان پشته‌ها

متدهای فهرست استفاده از یک فهرست به‌عنوان پشته را بسیار آسان می‌کنند؛ جایی که آخرین عنصری که اضافه می‌شود، اولین عنصری است که دریافت می‌شود («آخرین ورودی، اولین خروجی»). برای افزودن یک آیتم به بالای پشته، از append() استفاده کنید. برای دریافت یک آیتم از بالای پشته، از pop() بدون یک اندیس صریح استفاده کنید. برای مثال:

>>> stack = [3, 4, 5]
>>> stack.append(6)
>>> stack.append(7)
>>> stack
[3, 4, 5, 6, 7]
>>> stack.pop()
7
>>> stack
[3, 4, 5, 6]
>>> stack.pop()
6
>>> stack.pop()
5
>>> stack
[3, 4]

5.1.2. استفاده از فهرست‌ها به‌عنوان صف

It is also possible to use a list as a queue, where the first element added is the first element retrieved ("first-in, first-out"); however, lists are not efficient for this purpose. While appends and pops from the end of list are fast, doing inserts or pops from the beginning of a list is slow (because all of the other elements have to be shifted by one). See Time complexity of operations on built-in types for more information.

برای پیاده‌سازی صف، از collections.deque استفاده کنید که برای داشتن افزودن و حذف سریع از هر دو انتها طراحی شده است. برای مثال:

>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry")           # Terry arrives
>>> queue.append("Graham")          # Graham arrives
>>> queue.popleft()                 # The first to arrive now leaves
'Eric'
>>> queue.popleft()                 # The second to arrive now leaves
'John'
>>> queue                           # Remaining queue in order of arrival
deque(['Michael', 'Terry', 'Graham'])

5.1.3. درک‌های فهرستی

درک‌های فهرستی روشی کوتاه و مختصر برای ایجاد فهرست‌ها فراهم می‌کنند. کاربردهای رایج آن‌ها ایجاد فهرست‌های جدیدی است که در آن‌ها هر عنصر، نتیجه‌ی انجام برخی عملیات روی هر عضو از یک دنباله یا شیء پیمایش‌پذیر دیگر است، یا ایجاد یک زیردنباله از عناصری که یک شرط مشخص را برآورده می‌کنند.

برای مثال، فرض کنید می‌خواهیم فهرستی از مربع‌ها ایجاد کنیم، مانند:

>>> squares = []
>>> for x in range(10):
...     squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

توجه کنید که این کار یک متغیر با نام x ایجاد می‌کند (یا مقدار آن را بازنویسی می‌کند) که پس از پایان حلقه نیز همچنان وجود دارد. می‌توانیم فهرست مربع‌ها را بدون هیچ اثر جانبی با استفاده از روش زیر محاسبه کنیم:

squares = list(map(lambda x: x**2, range(10)))

یا به‌صورت معادل:

squares = [x**2 for x in range(10)]

که مختصرتر و خواناتر است.

یک درک فهرستی شامل کروشه‌هایی است که یک عبارت را در خود دارند و پس از آن یک بند for و سپس صفر یا چند بند for یا if قرار می‌گیرد. نتیجه، یک فهرست جدید خواهد بود که از ارزیابی عبارت در زمینه‌ی بندهای for و if پس از آن به‌دست می‌آید. برای مثال، این درک فهرستی عناصر دو فهرست را در صورتی که برابر نباشند با یکدیگر ترکیب می‌کند:

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

مساوی است با:

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

توجه کنید که ترتیب دستورهای for و if در هر دو قطعه‌کد یکسان است.

اگر عبارت یک تاپل باشد (برای مثال (x, y) در مثال قبلی)، باید درون پرانتز قرار گیرد.

>>> vec = [-4, -2, 0, 2, 4]
>>> # create a new list with the values doubled
>>> [x*2 for x in vec]
[-8, -4, 0, 4, 8]
>>> # filter the list to exclude negative numbers
>>> [x for x in vec if x >= 0]
[0, 2, 4]
>>> # apply a function to all the elements
>>> [abs(x) for x in vec]
[4, 2, 0, 2, 4]
>>> # call a method on each element
>>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
>>> [weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
>>> # create a list of 2-tuples like (number, square)
>>> [(x, x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
>>> # the tuple must be parenthesized, otherwise an error is raised
>>> [x, x**2 for x in range(6)]
  File "<stdin>", line 1
    [x, x**2 for x in range(6)]
     ^^^^^^^
SyntaxError: did you forget parentheses around the comprehension target?
>>> # flatten a list using a listcomp with two 'for'
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

درک‌های فهرستی می‌توانند شامل عبارت‌های پیچیده و توابع تودرتو باشند:

>>> from math import pi
>>> [str(round(pi, i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']

5.1.4. درک‌های فهرستی تودرتو

عبارت اولیه در یک درک فهرستی می‌تواند هر عبارت دلخواهی باشد، از جمله یک درک فهرستی دیگر.

مثال زیر را در نظر بگیرید که یک ماتریس 3x4 را به‌صورت یک فهرست شامل 3 فهرست با طول 4 پیاده‌سازی می‌کند:

>>> matrix = [
...     [1, 2, 3, 4],
...     [5, 6, 7, 8],
...     [9, 10, 11, 12],
... ]

درک فهرستی زیر ردیفها و ستون‌ها را جابه‌جا می‌کند:

>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

همان‌طور که در بخش قبل دیدیم، درک فهرستی داخلی در زمینه‌ی for که پس از آن قرار گرفته است ارزیابی می‌شود؛ بنابراین این مثال معادل است با:

>>> transposed = []
>>> for i in range(4):
...     transposed.append([row[i] for row in matrix])
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

که به نوبه‌ی خود، همانند این است:

>>> transposed = []
>>> for i in range(4):
...     # the following 3 lines implement the nested listcomp
...     transposed_row = []
...     for row in matrix:
...         transposed_row.append(row[i])
...     transposed.append(transposed_row)
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

در دنیای واقعی، بهتر است از توابع توکار به‌جای دستورهای جریان کنترل پیچیده استفاده کنید. تابع zip() برای این مورد کاربرد بسیار خوبی دارد:

>>> list(zip(*matrix))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

برای جزئیات درباره‌ی ستاره در این خط، به واگشایی آرگومان‌ها مراجعه کنید.

5.2. دستور del

روشی برای حذف یک آیتم از فهرست با استفاده از اندیس آن به‌جای مقدار آن وجود دارد: دستور del. این دستور با متد pop() که یک مقدار برمی‌گرداند تفاوت دارد. دستور del همچنین می‌تواند برای حذف اسلایس‌هایی از یک فهرست یا خالی کردن کامل فهرست استفاده شود (که پیش‌تر با انتساب یک فهرست خالی به اسلایس انجام دادیم). برای مثال:

>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.25, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.25, 1234.5]
>>> del a[:]
>>> a
[]

del همچنین می‌تواند برای حذف کامل متغیرها استفاده شود:

>>> del a

ارجاع دادن به نام a پس از این نقطه یک خطا است (حداقل تا زمانی که مقدار دیگری به آن اختصاص داده شود). بعداً کاربردهای دیگری برای del خواهیم یافت.

5.3. تاپل‌ها و دنباله‌ها

دیدیم که فهرست‌ها و رشته‌ها ویژگی‌های مشترک بسیاری مانند عملیات اندیس‌گذاری و اسلایس دارند. آن‌ها دو نمونه از نوع‌های داده‌ی دنباله‌ای (به Sequence Types --- list, tuple, range مراجعه کنید) هستند. از آنجا که پایتون زبانی در حال تکامل است، ممکن است نوع‌های داده‌ی دنباله‌ای دیگری نیز به آن افزوده شوند. همچنین یک نوع داده‌ی دنباله‌ای استاندارد دیگر وجود دارد: تاپل.

یک تاپل از تعدادی مقدار تشکیل شده است که با ویرگول از هم جدا شده‌اند، برای مثال:

>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
>>> # Tuples may be nested:
>>> u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
>>> # Tuples are immutable:
>>> t[0] = 88888
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> # but they can contain mutable objects:
>>> v = ([1, 2, 3], [3, 2, 1])
>>> v
([1, 2, 3], [3, 2, 1])

همان‌طور که می‌بینید، در خروجی تاپل‌ها همیشه درون پرانتز قرار می‌گیرند تا تاپل‌های تودرتو به‌درستی تفسیر شوند؛ آن‌ها می‌توانند با یا بدون پرانتزهای اطرافشان وارد شوند، اگرچه اغلب پرانتزها به هر حال لازم هستند (اگر تاپل بخشی از یک عبارت بزرگ‌تر باشد). امکان انتساب به آیتم‌های جداگانه‌ی یک تاپل وجود ندارد، بااین‌حال می‌توان تاپل‌هایی ایجاد کرد که شامل اشیای تغییرپذیر، مانند فهرست‌ها، باشند.

اگرچه تاپل‌ها ممکن است شبیه فهرست‌ها به نظر برسند، اغلب در موقعیت‌ها و برای اهداف متفاوتی استفاده می‌شوند. تاپل‌ها تغییرناپذیر هستند و معمولاً شامل یک دنباله‌ی ناهمگن از عناصر هستند که از طریق واگشایی (در ادامه‌ی این بخش توضیح داده می‌شود) یا اندیس‌گذاری (یا حتی از طریق ویژگی‌ها در مورد namedtuples) به آن‌ها دسترسی پیدا می‌شود. فهرست‌ها تغییرپذیر هستند و عناصر آن‌ها معمولاً همگن هستند و با پیمایش روی فهرست به آن‌ها دسترسی پیدا می‌شود.

یک مسئله‌ی ویژه، ساخت تاپل‌هایی است که شامل 0 یا 1 آیتم هستند: سینتکس زبان برای سازگاری با این موارد چند نکته‌ی خاص دارد. تاپل‌های خالی با یک جفت پرانتز خالی ساخته می‌شوند؛ یک تاپل با یک آیتم با قرار دادن یک ویرگول پس از یک مقدار ساخته می‌شود (قرار دادن یک مقدار تنها درون پرانتز کافی نیست). زشت، اما مؤثر. برای مثال:

>>> empty = ()
>>> singleton = 'hello',    # <-- note trailing comma
>>> len(empty)
0
>>> len(singleton)
1
>>> singleton
('hello',)

دستور t = 12345, 54321, 'hello!' نمونه‌ای از بسته‌بندی تاپل (tuple packing) است: مقدارهای 12345، 54321 و 'hello!' در یک تاپل بسته‌بندی می‌شوند. عملیات معکوس نیز امکان‌پذیر است:

>>> x, y, z = t

این عملیات، به‌درستی، واگشایی دنباله (sequence unpacking) نامیده می‌شود و برای هر دنباله‌ای در سمت راست کار می‌کند. واگشایی دنباله نیاز دارد که در سمت چپ علامت مساوی به همان تعداد عناصر موجود در دنباله، متغیر وجود داشته باشد. توجه کنید که انتساب چندگانه در واقع ترکیبی از بسته‌بندی تاپل و واگشایی دنباله است.

5.4. مجموعه‌ها

پایتون همچنین یک نوع داده برای مجموعه‌ها دارد. یک مجموعه، مجموعه‌ای نامرتب از عناصر بدون مقدارهای تکراری است. کاربردهای پایه‌ی آن شامل بررسی عضویت و حذف ورودی‌های تکراری است. اشیای مجموعه همچنین از عملیات ریاضی مانند اجتماع، اشتراک، تفاضل و تفاضل متقارن پشتیبانی می‌کنند.

از آکولادها یا تابع set() می‌توان برای ایجاد مجموعه‌ها استفاده کرد. توجه: برای ایجاد یک مجموعه‌ی خالی باید از set() استفاده کنید، نه {}؛ مورد دوم یک دیکشنری خالی ایجاد می‌کند، که یک ساختار داده است و در بخش بعدی درباره‌ی آن صحبت می‌کنیم.

از آنجا که مجموعه‌ها نامرتب هستند، پیمایش روی آن‌ها یا چاپ کردنشان ممکن است عناصر را با ترتیبی متفاوت از چیزی که انتظار دارید تولید کند.

در اینجا یک نمایش کوتاه ارائه شده است:

>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)                      # show that duplicates have been removed
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket                 # fast membership testing
True
>>> 'crabgrass' in basket
False

>>> # Demonstrate set operations on unique letters from two words
>>>
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a                                  # unique letters in a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b                              # letters in a but not in b
{'r', 'd', 'b'}
>>> a | b                              # letters in a or b or both
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b                              # letters in both a and b
{'a', 'c'}
>>> a ^ b                              # letters in a or b but not both
{'r', 'd', 'b', 'm', 'z', 'l'}

مانند درک‌های فهرستی، درک‌های مجموعه نیز پشتیبانی می‌شوند:

>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}

5.5. دیکشنری‌ها

یک نوع داده‌ی مفید دیگر که به‌صورت توکار در پایتون وجود دارد، دیکشنری است (به Mapping Types --- dict مراجعه کنید). دیکشنری‌ها در برخی زبان‌های دیگر با نام «حافظه‌های انجمنی» یا «آرایه‌های انجمنی» شناخته می‌شوند. برخلاف دنباله‌ها که با یک بازه از اعداد اندیس‌گذاری می‌شوند، دیکشنری‌ها با کلیدها اندیس‌گذاری می‌شوند؛ کلیدها می‌توانند هر نوع تغییرناپذیری باشند؛ رشته‌ها و اعداد همیشه می‌توانند کلید باشند. تاپل‌ها نیز می‌توانند به‌عنوان کلید استفاده شوند، اگر فقط شامل رشته‌ها، اعداد یا تاپل‌ها باشند؛ اگر یک تاپل به‌صورت مستقیم یا غیرمستقیم شامل یک شیء تغییرپذیر باشد، نمی‌توان از آن به‌عنوان کلید استفاده کرد. نمی‌توانید از فهرست‌ها به‌عنوان کلید استفاده کنید، زیرا فهرست‌ها را می‌توان با استفاده از انتساب اندیسی، انتساب اسلایس، یا متدهایی مانند append() و extend() در محل تغییر داد.

بهترین روش این است که یک دیکشنری را به‌عنوان مجموعه‌ای از جفت‌های کلید: مقدار در نظر بگیرید، با این شرط که کلیدها (درون یک دیکشنری) یکتا باشند. یک جفت آکولاد یک دیکشنری خالی ایجاد می‌کند: {}. قرار دادن یک فهرست جداشده با ویرگول از جفت‌های کلید:مقدار درون آکولاد، جفت‌های اولیه‌ی کلید:مقدار را به دیکشنری اضافه می‌کند؛ این همان روشی است که دیکشنری‌ها در خروجی نوشته می‌شوند.

عملیات اصلی روی یک دیکشنری، ذخیره کردن یک مقدار با یک کلید مشخص و استخراج مقدار با استفاده از کلید است. همچنین امکان حذف یک جفت کلید:مقدار با استفاده از del وجود دارد. اگر مقداری را با کلیدی ذخیره کنید که از قبل استفاده شده است، مقدار قدیمی مرتبط با آن کلید فراموش می‌شود.

استخراج مقدار برای کلیدی که وجود ندارد با استفاده از زیرنویسی (d[key]) باعث رخ دادن KeyError می‌شود. برای جلوگیری از دریافت این خطا هنگام تلاش برای دسترسی به کلیدی که ممکن است وجود نداشته باشد، به‌جای آن از متد get() استفاده کنید؛ این متد اگر کلید در دیکشنری وجود نداشته باشد، None (یا یک مقدار پیش‌فرض مشخص‌شده) را برمی‌گرداند.

اجرای list(d) روی یک دیکشنری، فهرستی از تمام کلیدهای استفاده‌شده در دیکشنری را با ترتیب درج آن‌ها برمی‌گرداند (اگر می‌خواهید مرتب شده باشد، فقط از sorted(d) استفاده کنید). برای بررسی اینکه یک کلید مشخص در دیکشنری وجود دارد یا نه، از کلیدواژه‌ای in استفاده کنید.

در اینجا یک مثال کوچک با استفاده از یک دیکشنری آورده شده است:

>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'jack': 4098, 'sape': 4139, 'guido': 4127}
>>> tel['jack']
4098
>>> tel['irv']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'irv'
>>> print(tel.get('irv'))
None
>>> del tel['sape']
>>> tel['irv'] = 4127
>>> tel
{'jack': 4098, 'guido': 4127, 'irv': 4127}
>>> list(tel)
['jack', 'guido', 'irv']
>>> sorted(tel)
['guido', 'irv', 'jack']
>>> 'guido' in tel
True
>>> 'jack' not in tel
False

سازنده‌ی dict() دیکشنری‌ها را مستقیماً از دنباله‌هایی از جفت‌های کلید-مقدار ایجاد می‌کند:

>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}

علاوه بر این، درک‌های دیکشنری می‌توانند برای ایجاد دیکشنری‌ها از عبارت‌های دلخواه کلید و مقدار استفاده شوند:

>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}

هنگامی که کلیدها رشته‌های ساده هستند، گاهی مشخص کردن جفت‌ها با استفاده از آرگومان‌های کلیدواژه‌ای آسان‌تر است:

>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}

5.6. تکنیک‌های حلقه‌زنی

هنگام پیمایش روی دیکشنری‌ها، کلید و مقدار متناظر آن را می‌توان به‌طور همزمان با استفاده از متد items() دریافت کرد.

>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
...     print(k, v)
...
gallahad the pure
robin the brave

هنگام پیمایش روی یک دنباله، اندیس موقعیت و مقدار متناظر آن را می‌توان به‌طور همزمان با استفاده از تابع enumerate() دریافت کرد.

>>> for i, v in enumerate(['tic', 'tac', 'toe']):
...     print(i, v)
...
0 tic
1 tac
2 toe

برای پیمایش روی دو یا چند دنباله به‌طور همزمان، می‌توان ورودی‌های آن‌ها را با استفاده از تابع zip() جفت کرد.

>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
...     print('What is your {0}?  It is {1}.'.format(q, a))
...
What is your name?  It is lancelot.
What is your quest?  It is the holy grail.
What is your favorite color?  It is blue.

برای پیمایش روی یک دنباله به‌صورت معکوس، ابتدا دنباله را در جهت عادی مشخص کنید و سپس تابع reversed() را فراخوانی کنید.

>>> for i in reversed(range(1, 10, 2)):
...     print(i)
...
9
7
5
3
1

برای پیمایش روی یک دنباله با ترتیب مرتب‌شده، از تابع sorted() استفاده کنید که یک فهرست مرتب‌شده‌ی جدید برمی‌گرداند، بدون اینکه دنباله‌ی اصلی را تغییر دهد.

>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for i in sorted(basket):
...     print(i)
...
apple
apple
banana
orange
orange
pear

استفاده از set() روی یک دنباله، عناصر تکراری را حذف می‌کند. استفاده از sorted() همراه با set() روی یک دنباله، روشی رایج در پایتون برای پیمایش روی عناصر یکتای دنباله با ترتیب مرتب‌شده است.

>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
...     print(f)
...
apple
banana
orange
pear

گاهی هنگام پیمایش روی یک فهرست وسوسه می‌شویم که آن را تغییر دهیم؛ بااین‌حال، اغلب ساده‌تر و امن‌تر است که به‌جای آن یک فهرست جدید ایجاد کنیم.

>>> import math
>>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
>>> filtered_data = []
>>> for value in raw_data:
...     if not math.isnan(value):
...         filtered_data.append(value)
...
>>> filtered_data
[56.2, 51.7, 55.3, 52.5, 47.8]

5.7. اطلاعات بیشتر درباره‌ی شرط‌ها

شرط‌هایی که در دستورهای while و if استفاده می‌شوند، می‌توانند شامل هر عملگری باشند، نه فقط عملگرهای مقایسه‌ای.

عملگرهای مقایسه‌ای in و not in آزمون‌های عضویت هستند که مشخص می‌کنند آیا یک مقدار درون یک ظرف (یا خارج از آن) قرار دارد یا نه. عملگرهای is و is not بررسی می‌کنند که آیا دو شیء واقعاً همان شیء یکسان هستند یا خیر. تمام عملگرهای مقایسه‌ای اولویت یکسانی دارند که از اولویت تمام عملگرهای عددی پایین‌تر است.

مقایسه‌ها می‌توانند زنجیره‌ای باشند. برای مثال، a < b == c بررسی می‌کند که آیا a کوچک‌تر از b است و علاوه بر آن b با c برابر است.

مقایسه‌ها را می‌توان با استفاده از عملگرهای بولی and و or ترکیب کرد و نتیجه‌ی یک مقایسه (یا هر عبارت بولی دیگر) را می‌توان با not نقیض کرد. این عملگرها اولویت پایین‌تری نسبت به عملگرهای مقایسه‌ای دارند؛ در میان آن‌ها، not بالاترین اولویت و or پایین‌ترین اولویت را دارد، بنابراین A and not B or C معادل (A and (not B)) or C است. همانند همیشه، می‌توان از پرانتزها برای بیان ترکیب موردنظر استفاده کرد.

عملگرهای بولی and و or به‌اصطلاح عملگرهای کوتاه‌مدار هستند: آرگومان‌های آن‌ها از چپ به راست ارزیابی می‌شوند و ارزیابی به‌محض مشخص شدن نتیجه متوقف می‌شود. برای مثال، اگر A و C درست باشند اما B نادرست باشد، عبارت A and B and C عبارت C را ارزیابی نمی‌کند. هنگامی که یک عملگر کوتاه‌مدار به‌عنوان یک مقدار عمومی و نه به‌عنوان یک مقدار بولی استفاده می‌شود، مقدار بازگشتی آن آخرین آرگومان ارزیابی‌شده است.

امکان اختصاص دادن نتیجه‌ی یک مقایسه یا عبارت بولی دیگر به یک متغیر وجود دارد. برای مثال،

>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
>>> non_null = string1 or string2 or string3
>>> non_null
'Trondheim'

توجه کنید که در پایتون، برخلاف C، انتساب درون عبارت‌ها باید به‌صورت صریح با عملگر والروس := انجام شود. این کار از یک دسته رایج از مشکلات موجود در برنامه‌های C جلوگیری می‌کند: نوشتن = در یک عبارت، در حالی که منظور == بوده است.

5.8. مقایسه‌ی دنباله‌ها و انواع دیگر

اشیای دنباله‌ای معمولاً می‌توانند با اشیای دیگری از همان نوع دنباله مقایسه شوند. مقایسه از ترتیب لغت‌نامه‌ای (lexicographical) استفاده می‌کند: ابتدا دو آیتم اول با یکدیگر مقایسه می‌شوند و اگر متفاوت باشند، نتیجه‌ی مقایسه را تعیین می‌کنند؛ اگر برابر باشند، دو آیتم بعدی مقایسه می‌شوند و این روند ادامه پیدا می‌کند تا زمانی که یکی از دنباله‌ها به پایان برسد. اگر دو آیتمی که باید مقایسه شوند خودشان دنباله‌هایی از همان نوع باشند، مقایسه‌ی لغت‌نامه‌ای به‌صورت بازگشتی انجام می‌شود. اگر تمام آیتم‌های دو دنباله برابر مقایسه شوند، دنباله‌ها برابر در نظر گرفته می‌شوند. اگر یکی از دنباله‌ها زیردنباله‌ی ابتدایی دیگری باشد، دنباله‌ی کوتاه‌تر، کوچک‌تر (کمتر) در نظر گرفته می‌شود. ترتیب لغت‌نامه‌ای برای رشته‌ها از شماره‌ی نقطه‌ی کد یونیکد برای مرتب‌سازی نویسه‌های منفرد استفاده می‌کند. چند نمونه از مقایسه‌ی دنباله‌های هم‌نوع:

(1, 2, 3)              < (1, 2, 4)
[1, 2, 3]              < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'
(1, 2, 3, 4)           < (1, 2, 4)
(1, 2)                 < (1, 2, -1)
(1, 2, 3)             == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)

توجه کنید که مقایسه‌ی اشیای نوع‌های مختلف با < یا > در صورتی مجاز است که اشیا متدهای مقایسه‌ی مناسب داشته باشند. برای مثال، نوع‌های عددی ترکیبی بر اساس مقدار عددی خود مقایسه می‌شوند، بنابراین 0 با 0.0 برابر است و موارد مشابه. در غیر این صورت، مفسر به‌جای ارائه‌ی یک ترتیب دلخواه، یک استثنای TypeError پرتاب می‌کند.

پانویس‌ها