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)  # کلمه‌ی banana بعدی که در موقعیت ۴ شروع میشود
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. استفاده از فهرست‌ها به‌عنوان صف

همچنین می‌توان از یک فهرست به‌عنوان صف استفاده کرد؛ جایی که اولین عنصری که اضافه می‌شود، اولین عنصری است که دریافت می‌شود («اولین ورودی، اولین خروجی»). بااین‌حال، فهرست‌ها برای این منظور کارایی مناسبی ندارند. در حالی که افزودن و حذف از انتهای فهرست سریع است، انجام درج یا حذف از ابتدای فهرست کند است (زیرا تمام عناصر دیگر باید یک موقعیت جابه‌جا شوند).

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

>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry")           # تری از راه میرسد
>>> queue.append("Graham")          # گراهام از راه میرسد
>>> queue.popleft()                 # اولین کسی که آمده حالا میرود
'Eric'
>>> queue.popleft()                 # یکی مانده به آخرین کسی که آمده حالا میرود
'John'
>>> queue                           # باقی مانده صف به ترتیب آمدن
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]
>>> # ایجاد یک فهرست جدید با مقادیر دو برابر شده
>>> [x*2 for x in vec]
[-8, -4, 0, 4, 8]
>>> # فیلتر کردن فهرست برای حذف اعداد منفی
>>> [x for x in vec if x >= 0]
[0, 2, 4]
>>> # اعمال یک تابع روی تمام عناصر
>>> [abs(x) for x in vec]
[4, 2, 0, 2, 4]
>>> # فراخوانی یک متد روی هر عنصر
>>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
>>> [weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
>>> # ایجاد فهرستی از تاپل‌های ۲تایی به شکل (عدد، مربع عدد)
>>> [(x, x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
>>> # تاپل باید داخل پرانتز قرار بگیرد، در غیر این صورت خطا ایجاد می‌شود
>>> [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?
>>> # تخت کردن یک فهرست با استفاده از listcomp و دو حلقه‌ی 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):
...     # سه خط بعدی، پیاده‌سازی list comprehension تو در تو را انجام می‌دهند
...     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!')
>>> # تاپل‌ها می‌توانند تو در تو باشند:
>>> u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
>>> # تاپل‌ها تغییرناپذیر هستند:
>>> t[0] = 88888
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> # اما می‌توانند شامل اشیای تغییرپذیر باشند:
>>> v = ([1, 2, 3], [3, 2, 1])
>>> v
([1, 2, 3], [3, 2, 1])

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

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

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

>>> empty = ()
>>> singleton = 'hello',    # <-- به وجود کامای انتهایی توجه کنید
>>> 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() می‌توان برای ایجاد مجموعه‌ها استفاده کرد. توجه: برای ایجاد یک مجموعهٔ خالی باید از set() استفاده کنید، نه {}؛ مورد دوم یک دیکشنری خالی ایجاد می‌کند، که یک ساختار داده است و در بخش بعدی دربارهٔ آن صحبت می‌کنیم.

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

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

>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)                      # نشان می‌دهد که موارد تکراری حذف شده‌اند
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket                 # بررسی سریع وجود یک عضو
True
>>> 'crabgrass' in basket
False

>>> # نمایش عملیات مجموعه‌ها روی حروف یکتای دو کلمه
>>>
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a                                  # حروف یکتای موجود در a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b                              # حروفی که در a هستند اما در b نیستند
{'r', 'd', 'b'}
>>> a | b                              # حروفی که در a یا b یا هر دو وجود دارند
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b                              # حروفی که هم در a و هم در b وجود دارند
{'a', 'c'}
>>> a ^ b                              # حروفی که در a یا b هستند اما در هر دو نیستند
{'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، انتساب درون عبارت‌ها باید به‌صورت صریح با عملگر walrus := انجام شود. این کار از یک دستهٔ رایج از مشکلات موجود در برنامه‌های 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 پرتاب می‌کند.

پانویس‌ها