list مجموعهای تغییرپذیر از عنصرها بهصورت پشت سر هم است.
مانند بیشتر مجموعهها (_به tuple، dict و set توکار نگاه کنید)، لیستها میتوانند ارجاعی به هر نوع داده (یا چند نوع داده) را نگه دارند، از جمله لیستهای دیگر.
در پایتون، آنها یک توالی در نظر گرفته میشوند و میتوان کل آنها یا بخشی از آنها را با slice notation کپی کرد.
مانند هر توالی، عنصرهای درون lists را میتوان با شمارهی 0-based index از سمت چپ، یا با شمارهی -1-based index از سمت راست ارجاع داد.
لیستها هم عملیات توالی متداول و هم عملیات توالی تغییرپذیر را پشتیبانی میکنند، مانند min(<list>)/max(<list>)، <list>.index()، <list>.append() و <list>.reverse().
میتوان با ساختار for item in <list> روی عنصرها پیمایش کرد و وقتی هم به عنصر و هم به اندیس آن نیاز باشد، از for index, item in enumerate(<list>) استفاده کرد.
پایتون متدهای مفید زیادی برای کار با لیستها ارائه میدهد.
چون لیستها تغییرپذیرند، متدهای لیست شیء لیست اصلی را که به متد داده شده تغییر میدهند.
اگر تغییر نامطلوب باشد، باید یک shallow copy (حداقل) از list اصلی با slice یا <list>.copy() ساخته شود.
افزودن عنصر به انتهای یک لیست موجود را میتوان با <list>.append(<item>) انجام داد:
>>> numbers = [1, 2, 3]
>>> numbers.append(9)
>>> numbers
[1, 2, 3, 9]
بهجای الحاق، <list>.insert(<index>, <item>) عنصر را به یک اندیس مشخص درون لیست اضافه میکند.
<index> اندیس عنصری است که میخواهید عنصر جدید پیش از آن ظاهر شود.
<item> عنصری است که باید درج شود.
توجه: اگر <index> برابر ۰ باشد، عنصر به ابتدای لیست اضافه میشود.
اگر <index> بزرگتر از اندیس نهایی لیست باشد، عنصر در جایگاه نهایی اضافه میشود، معادل استفاده از <list>.append(<item>).
>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)
>>> numbers
[-2, 1, 2, 3]
>>> numbers.insert(1, 0)
>>> numbers
[-2, 0, 1, 2, 3]
یک iterable را میتوان با <list>.extend(<iterable>) با یک لیست موجود ترکیب کرد (یعنی این دو را به هم چسباند).
<list>.extend(<iterable>) آن iterable دادهشده را باز میکند و عنصرهایش را به همان ترتیب به انتهای لیست هدف اضافه میکند.
استفاده از <list>.append(<item>) در این حالت، سراسر iterable را بهعنوان یک عنصر واحد اضافه میکند.
>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]
>>> numbers.extend(other_numbers)
>>> numbers
[1, 2, 3, 5, 6, 7]
>>> numbers.extend([8, 9])
>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]
از <list>.remove(<item>) میتوان برای حذف یک عنصر از لیست استفاده کرد.
اگر عنصر در لیست نباشد، <list>.remove(<item>) یک ValueError پرتاب میکند.
>>> numbers = [1, 2, 3]
>>> numbers.remove(2)
>>> numbers
[1, 3]
# Trying to remove a value that is not in the list throws a ValueError.
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list
در عوض، استفاده از متد <list>.pop(<index>) یک عنصر را هم حذف میکند و هم آن را return میکند تا از آن استفاده شود.
<list>.pop(<index>) یک پارامتر اختیاری میگیرد: index عنصری که باید حذف و برگردانده شود.
اگر آرگومان اختیاری <index> مشخص نشود، آخرین عنصر لیست حذف و برگردانده میشود.
اگر <index> عددی بزرگتر از اندیس نهایی لیست باشد، یک IndexError پرتاب میشود.
>>> numbers = [1, 2, 3]
>>> numbers.pop(0)
1
>>> numbers
[2, 3]
>>> numbers.pop()
3
>>> numbers
[2]
# This will throw an error because there is only index 0.
>>> numbers.pop(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
همهی عنصرها را میتوان با <list>.clear() از یک list حذف کرد. این متد هیچ پارامتری نمیگیرد.
>>> numbers = [1, 2, 3]
>>> numbers.clear()
>>> numbers
[]
ترتیب عنصرهای لیست را میتوان با <list>.reverse() درجا معکوس کرد. این کار لیست اصلی را تغییر میدهد.
>>> numbers = [1, 2, 3]
>>> numbers.reverse()
>>> numbers
[3, 2, 1]
یک لیست را میتوان به کمک <list>.sort() درجا مرتب کرد.
ترتیب مرتبسازی پیشفرض از سمت چپ صعودی است.
مستندات پایتون نکات و تکنیکهای بیشتری برای مرتبسازی ارائه میدهد.
از سال ۲۰۰۲ تا ۲۰۲۲، پایتون بهصورت داخلی از الگوریتمی به نام Timsort برای مرتبکردن لیستها استفاده میکرد، اما از Python 3.11 به بعد به Powersort روی آورد.
میتوانید جزئیات و بحث بیشتر دربارهی این تغییر را از تیم اصلی پایتون در مسئلهی ۷۸۷۴۲ گیتهاب بخوانید.
برای جزئیات فنی این الگوریتم، مقالهی J. Ian Munro و Sebastian Wild را ببینید: Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
# The default sort order is *ascending*.
>>> names.sort()
>>> names
["Bruce", "Natasha", "Thor", "Tony"]
برای مرتبکردن یک لیست به ترتیب نزولی، آرگومان reverse=True را به متد بدهید:
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)
>>> names
["Tony", "Thor", "Natasha", "Bruce"]
در مواردی که تغییر دادن list اصلی نامطلوب است، میتوان از توابع توکار sorted() و reversed() استفاده کرد.
sorted(<list>) یک کپی مرتبشده برمیگرداند و همان پارامترهای <list>.sort() را میگیرد.
reversed(<list>) یک پیمایشگر برمیگرداند که عنصرهای لیست را به ترتیب معکوس تولید میکند.
Iterators در تمرین دیگری بهتفصیل بررسی خواهد شد.
یافتن تعداد تکرارهای یک عنصر در لیست را میتوان به کمک <list>.count(<item>) انجام داد.
این متد تعداد کل بارهایی را برمیگرداند که <item> بهعنوان یک عنصر در لیست ظاهر میشود.
>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]
>>> items.count(1)
3
<list>.index(<item>) اندیسِ نخستین تکرارِ عنصر دادهشده را برمیگرداند.
اگر هیچ تکراری نباشد، یک ValueError پرتاب میشود.
اندیسگذاری از سمت چپ 0-based است، یعنی جایگاه عنصر اول اندیس 0 است.
اندیسگذاری از سمت راست نیز پشتیبانی میشود و از اندیس -1 شروع میشود.
>>> items = [7, 4, 1, 0, 2, 5]
>>> items.index(4)
1
>>> items.index(10)
ValueError: 10 is not in list
دادن اندیسهای start و end جستوجو را در بخش مشخصی از لیست انجام میدهد:
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> names.index("Tina")
0
>>> names.index("Tina", 2, 5)
3
اگر به جایگاه دقیق یک عنصر نیاز نباشد، عملگر توکار in برای بررسی عضویت کارآمدتر است.
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> "Thomas" in names
True
به یاد داشته باشید که متغیرها در پایتون اسمهایی هستند که به شیءهای زیربنایی اشاره میکنند.
اسمها میتوانند در طول عمر یک برنامه به شیءهای مختلف مقید یا دوباره مقید شوند.
اختصاص دادن یک شیء list به یک اسم متغیر جدید، شیء یا هیچیک از دادههای ارجاعشدهاش را کپی نمیکند.
اسم جدید و اسم قدیمی هر دو به یک شیء list یکسان اشاره خواهند کرد.
علاوه بر این، لیستها یک شیء از نوع container هستند: برای صرفهجویی در فضا، containerها فقط ارجاعهایی به عنصرهای عضو نگه میدارند، نه خود عنصرها.
این «بهینهسازی» میتواند برای افراد بیاحتیاط پیامدهای ناخواستهای داشته باشد.
<list>.copy() یک شیء list جدید میسازد، اما برای عنصرهای ارجاعشدهی لیست شیءهای جدید نمیسازد؛ این کپی «shallow» است.
یک shallow copy معمولاً کافی است، اگر بخواهید از یکی از شیءهای list عنصر اضافه یا حذف کنید بدون آنکه دیگری تغییر کند.
اما اگر هر احتمال این وجود داشته باشد که عنصرهای زیربنایی یک list بهطور تصادفی تغییر کنند (و در نتیجه همهی کپیهای shallow مرتبط هم تغییر کنند)، باید از copy.deepcopy() در ماژول copy استفاده کرد تا یک کپی کامل یا «deep» از همهی ارجاعها و شیءها ساخته شود.
برای توضیح مفصل دربارهی رفتار اسمها، مقدارها، لیست و لیستهای تودرتو، نگاهی به این پست وبلاگ عالی از Ned Batchelder بیندازید: Names and values: making a game board. Shallow vs Deep Copying of Python Objects هم مرور خوبی از نکات مربوط به کپی ارائه میدهد.