درس ۰۸: انواع آماده شی - بخش دوم

پایتون هر «نوع داده» (Data Type) را توسط یک کلاس ارایه می‌دهد؛ بنابراین هر داده یک نمونه یا یک شی از کلاسی مشخص است. هر چند برنامه‌نویس نیز می‌تواند با تعریف کلاس، نوع دلخواه خود را داشته باشد ولی در این درس می‌خواهیم درباره آن بخشی از انواع داده یا انواع شی‌ (Object Types) که به شکل آماده (Built-in) در اختیار مفسر زبان پایتون قرار داده شده است صحبت کنیم.

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

سطح: مقدماتی



لیست

نوع «لیست» (List) انعطاف‌ پذیرترین نوع آماده در پایتون می‌باشد. این نوع همانند رشته یک «دنباله» (Sequence) بوده ولی برخلاف آن یک نوع «تغییر پذیر» (Mutable) است. شی لیست با استفاده از کروشه [ ] ایجاد می‌گردد و می‌تواند عضوهایی - با هر نوع - داشته باشد که توسط کاما , از یکدیگر جدا می‌شوند؛ نوع لیست در واقع محلی برای نگهداری اشیا گوناگون است:

>>> L = [1, 2, 3]
>>> type(L)
<class 'list'>

>>> L
[1, 2, 3]
>>> print(L)
[1, 2, 3]

>>> import sys
>>> sys.getsizeof(L)
88
>>> L = []    # An empty list
>>> L
[]

عضوهای لیست می‌توانند از هر نوعی باشند؛ حتی یک لیست:

>>> L = [15, 3.14, 'string', [1, 2]]

شی لیست جزو انواع دنباله پایتون است و می‌توان عضوها را بر اساس اندیس موقعیت آن‌ها دستیابی نمود:

>>> L = [1, 2, 3]
>>> L[0]
1
>>> L[-1]
3

و همچنین تعداد عضوهای هر شی لیست را توسط تابع ()len [اسناد پایتون] به دست آورد:

>>> L1 = []
>>> len(L1)
0

>>> L2 = ['python', 12.06]
>>> len(L2)
2

>>> len(L2[0])
6

>>> L3 = ['a', [1, 2], 'b']
>>> len(L3)
3
>>> len(L3[1])
2

چنانچه یک دنباله جزو عضوهای شی لیست باشد، با استفاده از الگو [seq[i][j می‌توان عضوهای آن را نیز دستیابی نمود که در آن i اندیسی است که به یک عضو شی لیست اشاره دارد و j نیز اشاره به اندیس داخلی عضو i دارد؛ این الگو به همین شیوه می‌تواند ادامه یابد:

>>> L = ['python', 2.56]
>>> L[0]
'python'
>>> L[0][:2]
'py'

>>> L = ['python', 2.56, [128, ['a', 'z']]]
>>> L[2][1][0]
'a'

یکی از مثال‌های رایج شی لیست‌، شبیه‌سازی ساختار ماتریس (Matrix) است:

>>> L = [[1, 2, 3],
...      [4, 5, 6],
...      [7, 8, 9]]
>>>

>>> L
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

>>> L[0][1]
2

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

  • جایگزین کردن:

    >>> L = [1, 2, 3]
    
    >>> L[1] = 'py'
    >>> L
    [1, 'py', 3]
    
    >>> L = [1, 2, 3, 4, 5, 6]
    
    >>> L[:2] = [0, 0]
    >>> L
    [0, 0, 3, 4, 5, 6]
    
  • درج کردن - i در الگو [seq[i:i به موقعیتی از شی seq اشاره دارد که می‌خواهیم درج در آن نقطه انجام شود؛ در این شیوه توجه داشته باشید که شی‌ای که می‌خواهید درون لیست درج کنید می‌بایست یک دنباله باشد:

    >>> L = [0, 1, 5, 6]
    
    >>> L[2:2] = [2, 3, 4]
    >>> L
    [0, 1, 2, 3, 4, 5, 6]
    
    >>> L[0:0] = 'abc'
    >>> L
    ['a', 'b', 'c', 0, 1, 2, 3, 4, 5, 6]
    
    >>> L[3:3] = ['d', [-2, -1]]
    >>> L
    ['a', 'b', 'c', 'd', [-2, -1], 0, 1, 2, 3, 4, 5, 6]
    
  • حذف کردن - کافی است یک شی لیست خالی ([]) را به یک یا چند عضو از شی لیست مورد نظر انتساب دهیم:

    >>> L = [0, 1, 2, 3, 4, 5, 6]
    
    >>> L[2:5] = []
    >>> L
    [0, 1, 5, 6]
    

دستور del

با استفاده از دستور del [اسناد پایتون] نیز می‌توان یک عضو یا یک تکه از شی لیست را حذف کرد:

>>> L = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

>>> del L[2]
>>> L
['a', 'b', 'd', 'e', 'f', 'g']

>>> del L[1:4]
>>> L
['a', 'f', 'g']

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

>>> a = 5
>>> a
5

>>> del a

>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

انتساب چندگانه

می‌توان یک شی لیست - یا در کل یک شی دنباله - را به تعدادی نام انتساب داد و متغیرهای جداگانه‌ای ایجاد نمود؛ این عمل Unpacking خوانده می‌شود. در این شرایط مفسر پایتون هر عضو دنباله را با حفظ ترتیب به یکی از نام‌ها انتساب می‌دهد که در حالت عادی می‌بایست تعداد نام‌ها با عضوهای دنباله برابر باشد:

>>> L = [1.1, 2.2, 3.3, 4.4]

>>> a, b, c, d = L

>>> a
1.1
>>> b
2.2
>>> c
3.3
>>> d
4.4
>>> a, b = [1.1, 2.2, 3.3, 4.4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)

ولی می‌توان یکی از نام‌ها را توسط نماد * نشانه‌گذاری کرد؛ در این شرایط مفسر پایتون توازنی را بین عضوهای دنباله و نام‌ها ایجاد می‌کند که در این حالت تمام عضوهای اضافی - در قالب یک شی لیست - به نام نشانه‌گذاری شده انتساب داده می‌شود. البته باید توجه داشت که ترتیب عضوهای دنباله در هر شرایطی رعایت خواهد شد؛ به نمونه کدهای پایین توجه نمایید:

>>> L = [1.1, 2.2, 3.3, 4.4]

>>> a, b, *c = L

>>> a
1.1
>>> b
2.2
>>> c
[3.3, 4.4]
>>> *a, b = [1.1, 2.2, 3.3, 4.4]

>>> a
[1.1, 2.2, 3.3]
>>> b
4.4
>>> a, *b, c = [1.1, 2.2, 3.3, 4.4]

>>> a
1.1
>>> b
[2.2, 3.3]
>>> c
4.4
>>> a, b, c, *d = [1.1, 2.2, 3.3, 4.4]

>>> a
1.1
>>> b
2.2
>>> c
3.3
>>> d
[4.4]

کپی کردن

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

>>> L1 = [1, 2, 3]

>>> L2 = L1

>>> L2
[1, 2, 3]

>>> id(L1)
140254551721800
>>> id(L2)
140254551721800

عضوهای یک شی لیست تغییر پذیر هستند و باید توجه داشته باشیم اکنون که هر دو متغیر به یک شی اشاره دارند اگر توسط یکی از متغیرها، عضوهای شی مورد نظر تغییر داده شوند، مقدار مورد انتظار ما از شی متغیر دوم نیز تغییر خواهد کرد:

>>> L1 = [1, 2, 3]

>>> L2 = L1

>>> L1[0] = 7

>>> L1
[7, 2, 3]
>>> L2
[7, 2, 3]

اگر این موضوع را یک مشکل بدانیم برای رفع آن می‌توان از شی متغیر یک کپی ایجاد کرده و این کپی را به متغیر جدید نسبت دهیم؛ در این شرایط هر دو متغیر به اشیایی جداگانه در محل‌هایی متفاوت از حافظه اشاره خواهند داشت. در حالت عادی برای کپی کردن یک شی لیست نیاز به کار جدیدی نیست و می‌توان از اندیس گذاری [:] - به معنی تمامی عضوها - استفاده کرد:

>>> L1
[7, 2, 3]

>>> L2 = L1[:]

>>> L1
[7, 2, 3]
>>> L2
[7, 2, 3]

>>> id(L1)
140254551721928
>>> id(L2)
140254551721800

>>> L1[0] = 5

>>> L1
[5, 2, 3]
>>> L2
[7, 2, 3]
../_images/l08-python-list-assignment-01.png

ولی اگر شی لیست مورد نظر عضوهایی از نوع لیست (یا هر نوع تغییر پذیر دیگر) داشته باشد، مشکل فوق همچنان برای این عضوها باقی است. به نمونه کد و تصویر پایین توجه نمایید:

>>> L1 = [1, 2, [7, 8]]

>>> L2 = L1[:]
>>> L2
[1, 2, [7, 8]]

>>> L1[2][1] = 5

>>> L1
[1, 2, [7, 5]]
>>> L2
[1, 2, [7, 5]]

>>> id(L1)
140402644179400
>>> id(L2)
140402651379720

>>> id(L1[2])
140402644179080
>>> id(L2[2])
140402644179080
../_images/l08-python-list-assignment-02.png

در پایتون کپی شی به دو شیوه «سطحی» (Shallow Copy) و «عمیق» (Deep Copy) انجام می‌شود که به ترتیب توسط تابع‌های ()copy و ()deepcopy از درون ماژول copy در دسترس هستند [اسناد پایتون]. در شیوه کپی سطحی همانند کاری که پیش از این انجام دادیدم - یعنی انتساب با استفاده از اندیس [:] - اشیا داخلی کپی نمی‌شوند و تنها یک ارجاع جدید به آن‌ها داده می‌شود؛ در حالی که توسط شیوه کپی عمیق از تمامی اشیا (تغییر پذیر) داخلی نیز یک کپی ایجاد می‌گردد:

>>> L1 = [1, 2, [7, 8]]

>>> import copy
>>> L2 = copy.copy(L1)    # Shallow Copy

>>> L1[2][1] = 5

>>> L1
[1, 2, [7, 5]]
>>> L2
[1, 2, [7, 5]]
>>> L1 = [1, 2, [7, 8]]

>>> import copy
>>> L2 = copy.deepcopy(L1)    # Deep Copy

>>> L1[2][1] = 5

>>> L1
[1, 2, [7, 5]]
>>> L2
[1, 2, [7, 8]]

>>> id(L1)
140402651379656
>>> id(L2)
140402644179400

>>> id(L1[2])
140402644106312
>>> id(L2[2])
140402651379080

عملگرها برای لیست

می‌توان از عملگرهای + (برای پیوند لیست‌ها) و * (برای تکرار عضوهای لیست) بهره برد:

>>> [1, 2] + [2, 3] + [3, 4]
[1, 2, 2, 3, 3, 4]

>>> ['python'] * 3
['python', 'python', 'python']

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

>>> [1, 'python'] == [1, 'python']
True

>>> [1, 'python'] == [1, 'PYTHON']
False

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

>>> L = ['a', [1, 2]]

>>> 'b' not in L
True
>>> 2 in L
False
>>> [1, 2] in L
True

تفاوت عملگرهای == و is

نکته‌ای که در درس‌های پیش مطرح نشد، بیان تفاوت بین عملگر برابری و عملگر هویت است. پیش از ارایه توضیح به نمونه کد پایین توجه نمایید:

>>> a = 5
>>> b = a
>>> a == b
True
>>> a is b
True

>>> L1 = [1, 2, 3]
>>> L2 = L1
>>> L1 == L2
True
>>> L1 is L2
True

>>> L2 = L1[:]
>>> L1 == L2
True
>>> L1 is L2          # False!
False

از درس پنجم به یاد داریم که هر شی در پایتون حاوی یک «شناسه» (identity)، یک «نوع» (type) و یک «مقدار» (value) است. عملگر == دو شی را از نظر یکسان بودن «مقدار» مورد بررسی قرار می‌دهد در حالی که عملگر is دو شی را از نظر یکسان بودن «شناسه» (خروجی تابع ()id) یا همان نشانی آن‌ها در حافظه مورد بررسی قرار می‌دهد.

پیش از این هم بیان شده بود که مفسر پایتون برای صرفه‌جویی در زمان و حافظه از ساخت مجدد اشیا نوع «صحیح» و «رشته» کوچک موجود اجتناب می‌کند و تنها یک ارجاع جدید به آن‌ها می‌دهد. اما این موضوع در مورد اشیا دیگر درست نمی‌باشد و مفسر پایتون برای هر متغیری که برای این نوع اشیا تعریف می‌گردد یک شی جدید ایجاد می‌کند و به آن ارجاع می‌دهد:

>>> a = 5
>>> b = 5
>>> a == b
True
>>> a is b
True

>>> m = 'python'
>>> n = 'python'
>>> m == n
True
>>> m is n
True

>>> L1 = [1, 2, 3]
>>> L2 = [1, 2, 3]
>>> L1 == L2
True
>>> L1 is L2          # False!
False

تبدیل به شی لیست

با استفاده از کلاس ()list [اسناد پایتون] می‌توان یک شی لیست ایجاد کرد یا اشیایی که از نوع دنباله هستند را به یک شی لیست تبدیل نمود:

>>> a = 'python'
>>> type(a)
<class 'str'>

>>> b = list(a)
>>> type(b)
<class 'list'>

>>> b
['p', 'y', 't', 'h', 'o', 'n']
>>> L = list()
>>> L
[]

متدهای کاربردی یک شی لیست

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

  • (append(x - شی x را به انتهای لیست مورد نظر اضافه می‌کند:

    >>> L = [1, 2, 3]
    
    >>> L.append(4)
    >>> L
    [1, 2, 3, 4]
    
    >>> L.append(['a', 'b'])
    >>> L
    [1, 2, 3, 4, ['a', 'b']]
    

    عملکرد این متد ((L.append(x) همانند عمل [L + [x است:

    >>> L = [1, 2, 3]
    >>> L + [4]
    [1, 2, 3, 4]
    
  • (extend(s - عضوهای شی دنباله s را به انتهای لیست مورد نظر اضافه می‌کند:

    >>> L = [1, 2, 3]
    
    >>> L.extend(['a', 'b'])
    >>> L
    [1, 2, 3, 'a', 'b']
    
    >>> L = [1, 2, 3]
    
    >>> L.extend('py')
    >>> L
    [1, 2, 3, 'p', 'y']
    
  • (insert(i, x - یک عضو جدید (مانند x) را در موقعیتی از لیست با اندیس دلخواه (مانند i) قرار می‌دهد:

    >>> L = [1, 2, 3]
    
    >>> L.insert(0, 'python')
    >>> L
    ['python', 1, 2, 3]
    
  • (remove(x - در لیست مورد نظر از سمت چپ به دنبال شی‌ x می‌گردد و نخستین مورد یافت شده را از لیست حذف می‌کند. چنانچه هیچ عضو برابری با شی x یافت نشود یک خطا گزارش می‌دهد:

    >>> L = [1, 2, 3, 5, 2 , 6 , 1]
    
    >>> L.remove(2)
    >>> L
    [1, 3, 5, 2, 6, 1]
    
    >>> L.remove(0)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: list.remove(x): x not in list
    

    توجه

    در مواردی که می‌خواهید اندیس خاصی از لیست را حذف نمایید؛ از دستور del استفاده کنید.

  • ([pop([i - عضو متناظر با اندیس i را از لیست حذف و به عنوان خروجی برمی‌گرداند. چنانچه اندیس به متد فرستاده نشود به صورت پیش‌فرض آخرین عضو از لیست مورد نظر را حذف و برمی‌گرداند:

    >>> L = ['a', 'b', 'c', 'd']
    
    >>> L.pop(2)
    'c'
    >>> L
    ['a', 'b', 'd']
    
    >>> L.pop()
    'd'
    >>> L
    ['a', 'b']
    

    توجه

    نماد [ ] در الگو متدها تنها روشی برای بیان اختیاری بودن عبارت درون آن می‌باشد و جزیی از متد نیست.

  • ([index(x[, n - در لیست مورد نظر از سمت چپ به دنبال شی x می‌گردد و اندیس نخستین مورد یافت شده را برمی‌گرداند. این متد یک آرگومان اختیاری (n) نیز دارد که به کمک آن می‌توان تعیین نمود اندیس چندمین مورد یافت شده برگردانده شود. چنانچه هیچ عضو برابری با شی x یافت نشود یک خطا گزارش می‌دهد:

    >>> L = ['s', 'b', 'c', 'a', 's', 'b']
    
    >>> L.index('b')
    1
    
    >>> L.index('b', 2)
    5
    
    >>> L.index('z')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: 'z' is not in list
    
  • (count(x - تعداد وقوع شی x را در لیست مورد نظر برمی‌گرداند:

    >>> L = ['a', 'b', 'c', 'a', 'a', 'b']
    
    >>> L.count('a')
    3
    >>> L.count(5)
    0
    
  • ()clear - تمام عضوهای لیست مورد نظر را حذف می‌کند. عملکرد این متد معادل دستور [:]del L می‌باشد:

    >>> L = [0, 1, 2, 3, 4, 5]
    
    >>> L.clear()
    >>> L
    []
    
    >>> L = [0, 1, 2, 3, 4, 5]
    
    >>> del L[:]
    >>> L
    []
    
  • ()reverse - عضوهای لیست مورد نظر را وارونه می‌کند:

    >>> L = ['a', 'b', 'c', 'd']
    
    >>> L.reverse()
    >>> L
    ['d', 'c', 'b', 'a']
    
  • ()sort - عضوهای یک لیست را مرتب می‌کند:

    >>> L = [4, 6, 2, 1, 5, 0, 3]
    
    >>> L.sort()
    >>> L
    [0, 1, 2, 3, 4, 5, 6]
    
    >>> L = ['g', 'e', 'h', 'f', 'd']
    
    >>> L.sort()
    >>> L
    ['d', 'e', 'f', 'g', 'h']
    

    این متد در حالت پیش‌فرض به صورت صعودی اقدام به مرتب سازی می‌کند ولی می‌توان با فرستادن مقدار True به آرگومان اختیاری reverse، شیوه آن را به نزولی تغییر داد:

    >>> L = [4, 6, 2, 1, 5, 0, 3]
    
    >>> L.sort(reverse=True)
    >>> L
    [6, 5, 4, 3, 2, 1, 0]
    

    متد ()sort آرگومان اختیاری دیگری نیز با نام key دارد که می‌توان با ارسال یک تابع تک آرگومانی به آن عمل دلخواهی را بر روی تک تک عضوهای لیست مورد نظر، پیش از مقایسه و مرتب‌سازی به انجام رساند. البته باید توجه داشت که تنها می‌بایست نام تابع به آرگومان متد فرستاده شود و نه الگو کامل آن؛ برای مثال تابع با الگو (func(x باید به صورت key=func فرستاده شود. چنانچه آرگومان key فرستاده شود، این متد عضوهای لیست را به تابع تعیین شده می‌فرستد و در انتها خروجی آن‌ها را برای عمل مرتب‌سازی در نظر می‌گیرد. به نمونه کد پایین توجه نمایید:

    >>> L = ['a', 'D', 'c', 'B', 'e', 'f', 'G', 'h']
    
    >>> L.sort()
    >>> L
    ['B', 'D', 'G', 'a', 'c', 'e', 'f', 'h']
    

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

    >>> L = ['a', 'D', 'c', 'B', 'e', 'f', 'G', 'h']
    
    >>> L.sort(key=str.lower)
    >>> L
    ['a', 'B', 'c', 'D', 'e', 'f', 'G', 'h']
    

    در نمونه کد بالا str.lower به چه معنی است؟

    در درس پیش با کلاس ()str که از آن برای ایجاد شی رشته استفاده می‌شد آشنا شدیم و با برخی از متدهای آن که برای یک شی رشته در دسترس بود (مانند: ()join) نیز کار کردیم. در آینده توسط درس مربوط به کلاس‌ها خواهیم آموخت که می‌توان با استفاده از نام کلاس و بدون ایجاد شی، متدهای داخل آن را فراخوانی نمود؛ در اینجا نیز همین اتفاق افتاده است و (lower(s متدی تک آرگومانی داخل کلاس str می‌باشد که توسط نام این کلاس فراخوانی شده است.

    >>> str
    <class 'str'>
    
    >>> str.lower
    <method 'lower' of 'str' objects>
    
    >>> dir(str)
    ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
    

    نکته

    با استفاده از تابع آماده ()dir [اسناد پایتون] می‌توانیم لیستی از تمام صفت‌ها و متدهای در دسترس یک شی را دریافت نماییم.

    به جای متد ()sort می‌توان از تابع آماده ()sorted [اسناد پایتون] نیز با همین توضیح استفاده کرد:

    >>> L = ['a', 'D', 'c', 'B', 'e', 'f', 'G', 'h']
    
    >>> sorted(L)
    ['B', 'D', 'G', 'a', 'c', 'e', 'f', 'h']
    
    >>> sorted(L, key=str.lower, reverse=True)
    ['h', 'G', 'f', 'e', 'D', 'c', 'B', 'a']
    

ایجاد پشته

«پشته» (Stack) ساختاری برای نگهداری موقت داده‌ها می‌باشد به شکلی که آخرین داده‌ای که در آن قرار می‌گیرد نخستین داده‌ای خواهد بود که خارج می‌گردد؛ این شیوه سازمان‌دهی LIFO یا Last In, First Out خوانده می‌شود. پشته تنها از دو عمل (یا متد) پشتیبانی می‌کند: push که داده‌ای را بالای تمام داده‌های موجود در آن قرار می‌دهد و pop که بالاترین داده را از آن خارج می‌کند.

ساختار پشته را می‌توان به سادگی با استفاده از نوع لیست در پایتون پیاده‌سازی کرد؛ به این صورت که برای یک شی لیست متد ()append معادل عمل push و متد ()pop نیز معادل عمل pop خواهد بود:

>>> stack = []

>>> stack.append(1)
>>> stack.append(2)
>>> stack.append(3)

>>> stack
[1, 2, 3]

>>> stack.pop()
3
>>> stack.pop()
2

>>> stack
[1]

تاپل

نوع «تاپِل» (Tuple) همانند نوع list است ولی با این تفاوت که تغییر پذیر نیست و عضوهای آن درون پرانتز () قرار داده می‌شوند:

>>> t = (1, 2, 3)
>>> type(t)
<class 'tuple'>

>>> t
(1, 2, 3)
>>> print(t)
(1, 2, 3)

>>> import sys
>>> sys.getsizeof(t)
72
>>> t = ()    # An empty tuple
>>> t
()

در انتهای شی تاپل تک عضوی می‌بایست یک نماد کاما قرار داد؛ به مانند: (,1). از آنجا که از پرانتز در عبارت‌ها نیز استفاده می‌شود؛ با این کار مفسر پایتون یک شی تاپل را از عبارت تشخیص می دهد:

>>> (4 + 1)
5

>>> a = (1)
>>> a
1
>>> type(a)
<class 'int'>
>>> t = (1,)
>>> t
(1,)
>>> type(t)
<class 'tuple'>

برای ایجاد شی تاپل حتی می‌توان از گذاردن پرانتز صرف نظر کرد و تنها اشیا (یا عبارت‌ها) را با کاما از یکدیگر جدا نمود:

>>> 5,
(5,)
>>> 1, 2 , 'a', 'b'
(1, 2, 'a', 'b')
>>> t = 'p', 'y'
>>> t
('p', 'y')
>>> 5 > 1, True == 0 , 7-2
(True, False, 5)

توجه

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

به دلیل شباهت‌های بسیار شی تاپل به شی لیست از ارایه توضیحات تکراری اجتناب کرده و تنها به ذکر چند مثال در ارتباط با نوع تاپل می‌پردازیم:

>>> ('a', 'b', 'c') + (1 , 2, 3)
('a', 'b', 'c', 1, 2, 3)

>>> ('python', 0) * 3
('python', 0, 'python', 0, 'python', 0)
>>> t = ('p', 'y', [1, 2, 3], 5)

>>> 'p' in t
True
>>> 2 not in t
True
>>> [1, 2, 3] not in t
False
>>> (1, 'python') == (1, 'python')
True
>>> (1, 'python') == (1, 'PYTHON')
False
>>> t1 = (1, 2, 3)
>>> t2 = t1
>>> t2 == t1
True
>>> t2 is t1
True

>>> t1 = (1, 2, 3)
>>> t2 = (1, 2, 3)
>>> t2 == t1
True
>>> t2 is t1
False
>>> t = ('p', 'y', [1, 2, 3], 5)

>>> t[0]
'p'
>>> t[-1]
5
>>> t[:2]
('p', 'y')
>>> t[2]
[1, 2, 3]
>>> t[2][1]
2

>>> t[0] = 'j'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t = ('p', 'y', [1, 2, 3], 5)

>>> len(t)
4
>>> len(t[2])
3

به دلیل ساختار ارجاعی بین اشیا در پایتون که توسط تصاویر بخش لیست نیز نمایش داده شد؛ اشیا تغییر پذیر درون شی تاپل، ویژگی‌های خود را داشته و همچنان تغییر پذیر خواهند بود:

>>> t = ('p', 'y', [1, 2, 3], 5)

>>> t[2][1] = 8
>>> t
('p', 'y', [1, 8, 3], 5)

همچنین به نمونه کدهای پایین در مورد Unpacking توجه نمایید:

>>> a, *b = (1.1, 2.2, 3.3, 4.4)

>>> a
1.1
>>> b
[2.2, 3.3, 4.4]
>>> a, *b, c = (1.1, 2.2, 3.3, 4.4)

>>> a
1.1
>>> b
[2.2, 3.3]
>>> c
4.4
>>> a, *b = [1.1, 2.2, (3.3, 4.4)]

>>> a
1.1
>>> b
[2.2, (3.3, 4.4)]
>>> a, *b, c = [1.1, 2.2, (3.3, 4.4)]

>>> a
1.1
>>> b
[2.2]
>>> c
(3.3, 4.4)
>>> a, *b, c = (1.1, 2.2, (3.3, 4.4))

>>> a
1.1
>>> b
[2.2]
>>> c
(3.3, 4.4)

حتما متوجه شده‌اید که عضوهای دنباله تنها با نوع لیست به نام نشانه‌گذاری شده انتساب داده می‌شود.

در هنگام انتساب متغیر تاپل به موضوع کپی نشدن اشیا تغییر پذیر توجه داشته باشید و در صورت نیاز از ماژول copy استفاده نمایید:

>>> t1 = ('p', 'y', [1, 2, 3], 5)

>>> t2 = t1                  # No Copy

>>> t1[2][1] = 8

>>> t1
('p', 'y', [1, 8, 3], 5)
>>> t2
('p', 'y', [1, 8, 3], 5)
>>> t1 = ('p', 'y', [1, 2, 3], 5)

>>> import copy
>>> t2 = copy.deepcopy(t1)    # Deep Copy

>>> t1[2][1] = 8

>>> t1
('p', 'y', [1, 8, 3], 5)
>>> t2
('p', 'y', [1, 2, 3], 5)

همانند شی لیست؛ شی تاپل نیز به دو متد ()index و ()count دسترسی دارد - این موضوع با استفاده از تابع ()dir قابل بررسی است:

>>> t = ('s', 'b', 'c', 'a', 's', 'b')
>>> dir(t)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
>>> t.index('b')
1

>>> t.index('b', 2)
5

>>> t.index('z')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: tuple.index(x): x not in tuple
>>> t.count('a')
3
>>> t.count(5)
0

استفاده از راهنما را که فراموش نکرده‌اید؟!:

>>> t = ('s', 'b', 'c', 'a', 's', 'b')

>>> help(t.index)

Help on built-in function index:

index(...) method of builtins.tuple instance
    T.index(value, [start, [stop]]) -> integer -- return first index of value.
    Raises ValueError if the value is not present.
(END)

هر زمان که نیاز به اِعمال تغییر در شی تاپل باشد؛ می‌توان شی مورد نظر را به صورت موقت به یک شی لیست تبدیل کرد. در این حالت می‌توان از ویژگی و متدهای شی لیست بهره برد و تغییرات دلخواه را اعمال کرد و در نهایت با یک تبدیل نوع دیگر دوباره به شی تاپل بازگشت. برای این منظور می‌توان با استفاده از کلاس ()list یک دنباله - در اینجا یک شی تاپل - را به شی لیست تبدیل کرد و در طرف دیگر توسط کلاس ()tuple نیز یک دنباله - در اینجا یک شی لیست - را به شی تاپل تبدیل نمود:

>>> t = (1, 2, 3)
>>> type(t)
<class 'tuple'>

>>> L = list(t)
>>> type(L)
<class 'list'>
>>> L
[1, 2, 3]

>>> L.insert(0, 'python')
>>> L
['python', 1, 2, 3]

>>> t = tuple(L)
>>> t
('python', 1, 2, 3)

البته در مواقعی که می‌خواهید عضوهای درون یک شی تاپل را مرتب (Sort) کنید، نیازی به تبدیل نوع لیست نمی‌باشد و می‌توانید از تابع ()sorted استفاده نمایید؛ این تابع مطابق آنچه که پیش از این معرفی شد یک شی تاپل را می‌گیرد و یک شی لیست با همان عضوها اما مرتب شده را برمی‌گرداند:

>>> t = ('a', 'D', 'c', 'B', 'e', 'f', 'G', 'h')

>>> sorted(t, key=str.lower, reverse=True)
['h', 'G', 'f', 'e', 'D', 'c', 'B', 'a']

کلاس ()tuple بدون آرگومان یک شی تاپل خالی را ایجاد می‌کند:

>>> t = tuple()
>>> t
()
>>> type(t)
<class 'tuple'>

دیکشنری

یکی دیگر از انواع انعطاف پذیر آماده در پایتون «دیکشنری» (Dictionary) می‌باشد که با نام کوتاه شده dict ارایه شده است. اشیا نوع دیکشنری با استفاده از نماد آکولاد { } معرفی‌ می‌شوند و هر داده در آن به شکل یک جفت «کلید:مقدار» (key:value) ذخیره می‌گردد. از این نوع شی با عنوان شی mapping (نگاشت) پایتون نیز یاد می‌شود چرا که در این نوع هر شی «کلید» به یک شی «مقدار» map یا نگاشت داده می‌شود. شی دیکشنری دنباله نیست ولی تغییر پذیر بوده و «مقدار» هر عضو توسط «کلید» متناظر با آن دستیابی می‌شود. شی «مقدار» می‌تواند از هر نوعی باشد حتی یک شی دیکشنری دیگر ولی شی «کلید» تنها می‌بایست از انواع «تغییر ناپذیر» انتخاب شود و باید توجه داشت که تمام «کلید»‌های یک شی دیکشنری می‌بایست «یکتا» (Unique) باشند.

>>> d = {1:'One', 2:'Two', 3:'Three'}

>>> type(d)
<class 'dict'>

>>> d
{1: 'One', 2: 'Two', 3: 'Three'}

>>> print(d)
{1: 'One', 2: 'Two', 3: 'Three'}

>>> import sys
>>> sys.getsizeof(d)
288

در نمونه کد بالا؛ اشیا 1، 2 و 3 کلید‌های شی d هستند که به ترتیب با اشیای 'One' و 'Two' و 'Three' نگاشت شده‌اند. برای دستیابی هر مقدار شی دیکشنری dic از الگو [dic[key استفاده می‌کنیم که key در آن، کلید متصل به مقدار مورد نظر می‌باشد:

>>> d = {1:'One', 2:'Two', 3:'Three'}

>>> d[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 0

>>> d[1]
'One'

>>> d[3][2:]
'ree'

[d[3 اشاره به مقدار 'Three' دارد؛ و از آنجا که این شی یک دنباله است می‌توان به روش دنباله‌ها (یعنی با استفاده از اندیس موقعیت) عضوهای این شی را نیز دستیابی نماییم.

به چند مثال دیگر توجه نمایید:

>>> d = {}    # An empty dictionary
>>> d
{}
>>> d = {'name': 'Bob', 'age': 40}

>>> d['name']
'Bob'
>>> d['age']
40
>>> d = {'cb4f2': {'name': 'Bob', 'age': 40}}

>>> d['cb4f2']['age']
40

ساختار نوع دیکشنری مشابه «جدول درهم‌سازی» (Hash table) است و کاربرد‌های فراوانی در الگوریتم‌های جستجو دارد. از این نوع همچنین می‌توان برای سازماندهی و ذخیره داده‌ها بر روی فایل استفاده کرد؛ برای نمونه فرض کنید می‌خواهیم چند فیلم با بازی Benedict Cumberbatch را به گونه‌ای در اختیار داشته باشیم که بتوانیم آن‌ها را بر اساس سال ساخت دستیابی نماییم:

>>> benedict_cumberbatch = {'2014':'The Imitation Game',
...                         '2013':('The Fifth Estate', '12 Years a Slave', 'Star Trek Into Darkness'),
...                         '2012':'The Hobbit: An Unexpected Journey',
...                         '2011':('War Horse', ' Wreckers', 'Tinker Tailor Soldier Spy')}
>>>

>>> benedict_cumberbatch['2014']
'The Imitation Game'

>>> len(benedict_cumberbatch['2011'])
3

>>> benedict_cumberbatch['2011'][0]
'War Horse'

از تابع ()len نیز می‌توان برای به دست آوردن تعداد عضوهای شی دیکشنری (جفتِ کلید:مقدار) استفاده کرد:

>>> d = {1:'One', 2:'Two', 3:'Three'}

>>> len(d)
3

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

>>> d = {'name': 'Bob', 'age': 40}

>>> d['name'] = 'Jhon'
>>> d
{'name': 'Jhon', 'age': 40}

>>> d['job'] = 'unemployed'
>>> d
{'name': 'Jhon', 'job': 'unemployed', 'age': 40}

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

با استفاده از دستوری مشابه [del dic[key نیز می‌توان یک عضو شی دیکشنری را حذف کرد:

>>> d = {'name': 'Jhon', 'job': 'unemployed', 'age': 40}

>>> del d['job']
>>> d
{'name': 'Jhon', 'age': 40}

امکانی برای تغییر کلیدها وجود ندارد مگر آنکه عضو مورد نظر را حذف کرده و یک عضو جدید (همان مقدار ولی با کلیدی جدید) اضافه نمایید:

>>> d = {'name': 'Jhon', 'job': 'unemployed', 'age': 40}

>>> d['occupation'] = d['job']
>>> del d['job']

>>> d
{'name': 'Jhon', 'age': 40, 'occupation': 'unemployed'}

عملگرها برای دیکشنری

عملگرهای + و * برای اشیا دیکشنری تعریف نشده‌اند.

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

>>> 'job' in {'name': 'Bob', 'age': 40}
False

>>> 'job' not in {'name': 'Bob', 'age': 40}
True

در مورد عملکرد عملگر برابری == و عملگرهای هویت (is و is not) صحبت شده است؛ این عملگرها برای اشیا دیکشنری نیز کاربرد دارند.

کپی کردن

همانطور که گفته شد شی دیکشنری از انواع «تغییر پذیر» پایتون است و همان توضیحاتی که در مورد شی لیست بیان شد؛ در اینجا هم درست است و گاهی نیاز می‌شود که از ماژول copy برای کپی اشیا دیکشنری استفاده نماییم:

  • بدون کپی کردن:

    >>> d1 = {'name': 'Bob', 'age': 40}
    
    >>> d2 = d1
    
    >>> d1 == d2
    True
    >>> d1 is d2
    True
    
    >>> d1['age'] = 46
    
    >>> d1
    {'name': 'Bob', 'age': 46}
    >>> d2
    {'name': 'Bob', 'age': 46}
    
  • کپی سطحی:

    >>> d1 = {'name': 'Bob', 'age': 40}
    
    >>> import copy
    >>> d2 = copy.copy(d1)              # shallow copy
    
    >>> d1 == d2
    True
    >>> d1 is d2                        # False!
    False
    
    >>> d1['age'] = 46
    
    >>> d1
    {'name': 'Bob', 'age': 46}
    >>> d2
    {'name': 'Bob', 'age': 40}
    
    >>> d1 = {'names': ['Bob', 'Jhon'], 'ages': [40, 40]}
    
    >>> import copy
    >>> d2 = copy.copy(d1)              # shallow copy
    
    >>> d1 == d2
    True
    >>> d1 is d2                        # False!
    False
    
    >>> d1['ages'][0] = 46
    
    >>> d1
    {'ages': [46, 40], 'names': ['Bob', 'Jhon']}
    
    >>> # d2 has changed!
    >>> d2
    {'ages': [46, 40], 'names': ['Bob', 'Jhon']}
    
  • کپی عمیق:

    >>> d1 = {'names': ['Bob', 'Jhon'], 'ages': [40, 40]}
    
    >>> import copy
    >>> d2 = copy.deepcopy(d1)          # deep copy
    
    >>> d1 == d2
    True
    >>> d1 is d2                        # False!
    False
    
    >>> d1['ages'][0] = 46
    
    >>> d1
    {'ages': [46, 40], 'names': ['Bob', 'Jhon']}
    >>> d2
    {'ages': [40, 40], 'names': ['Bob', 'Jhon']}
    

تبدیل به شی دیکشنری

برای تبدیل دیگر اشیا به نوع دیکشنری یا در کل ایجاد شی دیکشنری از کلاس ()dict [اسناد پایتون] استفاده می‌شود. توجه داشته باشید که عضوهای شی دیکشنری از طریق آرگومان‌ها و به شکل «کلید=مقدار» به کلاس فرستاده می‌شوند:

>>> d = dict(one=1, two=2, three=3)

>>> d
{'two': 2, 'one': 1, 'three': 3}
>>> d['one']
1

در این حالت برای انتخاب کلیدها باید قوانین انتخاب نام در پایتون را رعایت نماییم؛ برای مثال کلیدی که با عدد شروع شود مجاز نمی‌باشد.

برای فرستادن کلیدها و مقدارها می‌توانیم از تابع ()zip [اسناد پایتون] استفاده کنیم و خروجی این تابع را به عنوان آرگومان به کلاس dict ارسال کنیم. می‌توان اینگونه تصور کرد که این تابع تعدادی شی دنباله را می‌گیرد و عضوهای نظیر به نظیر آن‌ها را در کنار هم قرار می‌دهد؛ این دنباله‌ها باید تعداد عضو برابری داشته باشند؛ چرا که عضوهای اضافی هر دنباله نادیده گرفته می‌شود. خروجی ()zip یک شی جدید از نوع zip است و برای مشاهده معمولا آن را به نوع لیست تبدیل می‌کنند:

>>> k = [1, 2, 3, 4, 5]
>>> v = ['x', 'y', 'z']

>>> z = zip(k, v)

>>> z
<zip object at 0x7eff1d263548>

>>> type(z)
<class 'zip'>

>>> list(z)
[(1, 'x'), (2, 'y'), (3, 'z')]
>>> k = (1, 2, 3)
>>> v = ('One', 'Two', 'Three')

>>> d = dict(zip(k, v))

>>> d
{1: 'One', 2: 'Two', 3: 'Three'}

در آینده باز هم از تابع ()zip استفاده خواهیم کرد.

برخی از متدهای کاربردی یک شی دیکشنری

  • ()items [اسناد پایتون] تمام عضوهای شی را برمی‌گرداند - ()values [اسناد پایتون] تمام مقدارهای موجود در شی را بر می‌گرداند - ()keys [اسناد پایتون] تمام کلیدهای موجود در شی را بر می‌گرداند:

    >>> # Python 3.x
    
    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.items()
    dict_items([(1, 'One'), (2, 'Two'), (3, 'Three')])
    
    >>> d.values()
    dict_values(['One', 'Two', 'Three'])
    
    >>> d.keys()
    dict_keys([1, 2, 3])
    

    توجه داشته باشید که در نسخه‌های 3x پایتون خروجی این متدها از نوع متفاوتی است که با استفاده از ()type می‌توانید مشاهده کنید؛ این نوع dict_view نامیده می‌شود [اسناد پایتون 3x]. این متدها یک کپی از داده‌های مورد نظر (عضوها یا مقدارها یا کلیدها) را بر نمی‌گردانند بلکه می‌توان گفت پنجره‌ای برای مشاهده آنچه که هست باز می‌کنند و در هر زمان که این داده‌ها تغییر کنند این خروجی‌ها نیز تغییر می‌کنند. برای مشاهده بهتر این خروجی‌ها می‌توانید آن‌ها را به نوع لیست تبدیل نمایید:

    >>> list(d.items())
    [(1, 'One'), (2, 'Two'), (3, 'Three')]
    
    >>> list(d.values())
    ['One', 'Two', 'Three']
    
    >>> list(d.keys())
    [1, 2, 3]
    

    این متدها در پایتون 2x چنین خروجی ندارند و تنها یکی کپی از داده‌ها را برمی‌گردانند. البته در نسخه 2.7 متدهای معادلی با عنوان‌های ()viewitems [اسناد پایتون] و ()viewvalues [اسناد پایتون] و ()viewkeys [اسناد پایتون] پورت شده است:

    >>> # Python 2.7
    
    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.viewitems()
    dict_items([(1, 'One'), (2, 'Two'), (3, 'Three')])
    
    >>> d.viewvalues()
    dict_values(['One', 'Two', 'Three'])
    
    >>> d.viewkeys()
    dict_keys([1, 2, 3])
    
    >>> # Python 2.x
    
    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.items()
    [(1, 'One'), (2, 'Two'), (3, 'Three')]
    
    >>> d.values()
    ['One', 'Two', 'Three']
    
    >>> d.keys()
    [1, 2, 3]
    
  • ()clear [اسناد پایتون] - تمام عضوهای یک شی دیکشنری را حذف می‌کند:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.clear()
    >>> d
    {}
    
  • ()copy [اسناد پایتون] - این متد یک کپی سطحی از شی برمی‌گرداند:

    >>> d1 = {'name':'Bob'}
    
    >>> d2 = d1.copy()
    
    >>> d1 is d2
    False
    
  • (fromkeys(seq [اسناد پایتون] - یک دنباله از کلیدها را دریافت و یک شی جدید دیکشنری با استفاده از آن‌ها ایجاد می‌کند؛ البته کلیدهای این شی فاقد مقدار هستند که می‌بایست در زمانی دیگر به آن‌ها مقدار داد:

    >>> k = (1, 2, 3)   # or k=[1, 2, 3]  or  k='123'
    
    >>> dict.fromkeys(k)
    {1: None, 2: None, 3: None}
    

    توجه داشته باشید که این متد توسط خود کلاس dict فراخوانی می‌شود.

    این متد یک آرگومان اختیاری نیز دارد که توسط آن می‌توان یک شی را به عنوان «مقدار» پیش‌فرض کلید‌ها تعیین نمود:

    >>> k = (1, 2, 3)
    
    >>> dict.fromkeys(k, '-*-')
    {1: '-*-', 2: '-*-', 3: '-*-'}
    
  • (pop(key [اسناد پایتون] - عضو دارنده کلید key را حذف و مقدار آن را برمی‌گرداند. چنانچه عضوی با این کلید یافت نشود شی پیش‌فرض تعیین شده (آرگومان دوم که اختیاری است) را برمی‌گرداند و اگر این آرگومان ارسال نشده باشد یک خطا گزارش می‌دهد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.pop(2)
    'Two'
    >>> d
    {1: 'One', 3: 'Three'}
    
    >>> d.pop(2)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyError: 2
    
    >>> d.pop(2, 'Oops!')
    'Oops!'
    

    از این متد می‌توان برای تغییر راحت‌تر کلیدها استفاده کرد!:

    >>> d = {'name': 'Jhon', 'job': 'unemployed', 'age': 40}
    
    >>> d['occupation'] = d.pop('job')
    
    >>> d
    {'name': 'Jhon', 'age': 40, 'occupation': 'unemployed'}
    

    متد مشابه دیگری نیز با نام ()popitem [اسناد پایتون] - که بدون آرگومان است - در دسترس می‌باشد؛ این متد در هر فراخوانی یک عضو از شی مورد نظر را به صورت دلخواه حذف و به شکل تاپل (key, value) برمی‌گرداند و چنانچه دیکشنری خالی باشد یک خطا KeyError گزارش می‌دهد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.popitem()
    (1, 'One')
    
  • (get(key [اسناد پایتون] - مقدار مربوط به کلید key را برمی‌گرداند. چنانچه درون شی مورد نظر هیچ عضوی با این کلید وجود نداشته باشد شی پیش‌فرض تعیین شده (آرگومان دوم که اختیاری است) را برمی‌گرداند و اگر این آرگومان ارسال نشده باشد هیچ خطایی گزارش نمی‌دهد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.get(1)
    'One'
    
    >>> d.get(0)
    >>>
    
    >>> d.get(0, False)
    False
    
  • (setdefault(key [اسناد پایتون] - مقدار مربوط به کلید key را برمی‌گرداند. چنانچه عضوی با این کلید درون شی مورد نظر وجود نداشته باشد، کلید را به همراه مقدار پیش‌فرض تعیین شده (آرگومان دوم که اختیاری است) درون شی اضافه می‌کند و خود این مقدار را برمی‌گرداند؛ اگر آرگومان دوم ارسال نشده باشد به صورت پیش‌فرض مقدار None در نظر گرفته خواهد شد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.setdefault(1)
    'One'
    >>> d
    {1: 'One', 2: 'Two', 3: 'Three'}
    
    >>> d.setdefault(5)
    >>> d
    {1: 'One', 2: 'Two', 3: 'Three', 5: None}
    
    >>> d.setdefault(7, 'Seven')
    'Seven'
    >>> d
    {1: 'One', 2: 'Two', 3: 'Three', 5: None, 7: 'Seven'}
    
  • ()update [اسناد پایتون] - یک شی دیکشنری دیگر را به عنوان آرگومان می‌گیرد و عضوهای شی مورد نظر را بر اساس آن تغییر می‌دهد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d2 = {5:'Five', 6:'Six'}
    >>> d.update(d2)
    >>> d
    {1: 'One', 2: 'Two', 3: 'Three', 5: 'Five', 6: 'Six'}
    
    >>> d3 = {1:'0001'}
    >>> d.update(d3)
    >>> d
    {1: '0001', 2: 'Two', 3: 'Three', 5: 'Five', 6: 'Six'}
    

مجموعه

«مجموعه» (Set) از انواع «نامنظم» (Unordered) و «تغییر پذیر» (Mutable) پایتون است که معادل مفهوم مجموعه در ریاضیات می‌باشد. هر عضو مجموعه می‌بایست یکتا و یکی از انواع «تغییر ناپذیر» باشد. نوع مجموعه یا set در نسخه‌ 3x با کمی تفاوت ارایه شده است. در نسخه‌های 2x تنها می‌توان با استفاده از کلاس ()set [اسناد پایتون] اقدام به ایجاد این اشیا نمود در حالی که در پایتون 3x این کار به سادگی و تنها با استفاده از نماد آکولاد { } نیز امکان پذیر شده است؛ (البته این ویژگی به نسخه 2.7 هم پورت شده است). در دو نمونه کد پایین به چگونگی تعریف و نمایش شی مجموعه توجه نمایید:

نسخه‌های 2x:

>>> L = [1, 2, 3, 4, 5]

>>> s = set(L)

>>> type(s)
<type 'set'>

>>> s
set([1, 2, 3, 4, 5])

>>> print s
set([1, 2, 3, 4, 5])
>>> s = {1, 2, 3, 4, 5}    # Python 2.7

>>> type(s)
<type 'set'>

>>> s
set([1, 2, 3, 4, 5])

نسخه‌های 3x:

>>> L = [1, 2, 3, 4, 5]

>>> s = set(L)

>>> type(s)
<class 'set'>

>>> s
{1, 2, 3, 4, 5}

>>> print(s)
{1, 2, 3, 4, 5}
>>> s = {1, 2, 3, 4, 5}

>>> type(s)
<class 'set'>

>>> s
{1, 2, 3, 4, 5}

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

>>> a = {}       # Python 2.x
>>> type(a)
<type 'dict'>

>>> b = set()
>>> type(b)
<type 'set'>

>>> b
set([])
>>> a = {}       # Python 3.x
>>> type(a)
<class 'dict'>

>>> b = set()
>>> type(b)
<class 'set'>

>>> b
set()

از تابع ()len می‌توان برای به دست آوردن تعداد عضوهای یک شی مجموعه نیز استفاده کرد:

>>> s = {1, 2, 3, 4, 5}
>>> len(s)
5

عملگرها برای مجموعه

تعدادی از عملگرها هستند که برای اشیا مجموعه تعریف خاصی پیدا می‌کنند؛ در حالی که در مورد اشیا دیگر چنین رفتاری ندارند. این عملگرها در واقع پیاده‌سازی تعریف مشخصی در مفهوم ریاضی مجموعه‌ها هستند:

  • | اجتماع (Union): مانند A | B که حاصل آن مجموعه‌ای می‌باشد که تمام عضوهای مجموعه A و مجموعه B را داشته باشد و هیچ عضو اضافه دیگری نداشته باشد.

    >>> A | B
    {'w', 'y', 'q', 't', 'r', 'z', 's', 'v', 'u', 'x'}
    
  • & اشتراک (Intersection): مانند A & B که حاصل آن مجموعه‌ای می‌باشد که تنها شامل عضوهایی است که هم در مجموعه A هستند و هم در مجموعه B:

    >>> A & B
    {'w', 'v', 'u'}
    
  • - تفاضل (Difference): مانند A - B که حاصل آن مجموعه‌ای می‌باشد که تنها شامل عضوهایی از مجموعه A است كه در مجموعه B نيستند:

    >>> A = {'u', 'v', 'w', 'x', 'y', 'z'}
    >>> B = {'q', 'r', 's', 't', 'u', 'v', 'w',}
    
    >>> A - B
    {'z', 'y', 'x'}
    
  • ^ تفاضل متقارن (Symmetric difference): مانند A ^ B که حاصل آن مجموعه‌ای می‌باشد که برابر اجتماع ِ تفاضل A از B و تفاضل B از A می‌باشد یعنی: (A-B) | (B-A):

    >>> A ^ B
    {'q', 'y', 't', 'r', 'z', 's', 'x'}
    
    >>> (A-B) | (B-A)
    {'y', 'q', 't', 'r', 'z', 'x', 's'}
    

    تفاضل متقارن را می‌توان به صورت پایین نیز تعریف کرد:

    >>> (A|B) - (B&A)
    {'y', 'q', 't', 'r', 'z', 's', 'x'}
    
  • > زیرمجموعه (Subset): مانند A < B که اگر مجموعه A زیرمجموعه‌ای از مجموعه B باشد مقدار True را برمی‌گرداند. در مقابل عملگر < قرار دارد که برای مثال در عبارت A > B اگر مجموعه A یک Superset برای مجموعه B باشد مقدار True را برمی‌گرداند:

    >>> A = {1, 2, 3, 4, 5}
    >>> B = {1, 2, 3}
    
    >>> A < B
    False
    
    >>> A > B
    True
    

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

>>> A = {'a', 'b', 'c'}

>>> 'a' in A
True
>>> 'c' not in A
False
>>> A = {1, 2, 3, 4, 5}
>>> B = {1, 2, 3}

>>> A == B
False

>>> C = A

>>> A == C
True

>>> A is C
True

برخی از متدهای کاربردی یک شی مجموعه

  • ()union [اسناد پایتون] - تعدادی شی مجموعه را دریافت می‌کند و یک مجموعه جدید که برابر اجتماع شی مورد نظر با آن‌ها است را برمی‌گرداند:

    >>> A = {'a', 'b', 'c'}
    >>> B = {1, 2, 3}
    
    >>> {'t', 1, 'a'}.union(A, B)
    {'a', 1, 2, 3, 't', 'b', 'c'}
    
    >>> {'t', 1, 'a'} | A | B
    {1, 2, 3, 'b', 't', 'a', 'c'}
    

    به صورت مشابه می‌توان از متدهای ()intersection [اسناد پایتون] برای اشتراک، ()difference [اسناد پایتون] برای تفاضل، ()symmetric_difference [اسناد پایتون] - که تک آرگومانی است - برای تفاضل متقارن، ()issubset [اسناد پایتون] و ()issuperset [اسناد پایتون] - که هر دو تک آرگومانی هستند - برای بررسی زیرمجموعه یا Superset بودن استفاده کرد.

  • ()clear [اسناد پایتون] - تمام عضوهای یک شی مجموعه را حذف می‌کند:

    >>> A = {'a', 'b', 'c'}
    
    >>> A.clear()
    >>> A
    set()
    
  • (add(x [اسناد پایتون] - شی تغییر ناپذیر x را در صورتی که از قبل درون شی مجموعه مورد نظر وجود نداشته باشد به آن اضافه می‌کند:

    >>> A = {'a', 'b', 'c'}
    
    >>> A.add(1)
    >>> A
    {'a', 'c', 1, 'b'}
    
  • (remove(x [اسناد پایتون] - عضو x را از شی مجموعه مورد نظر حذف می‌کند. در صورتی که x درون مجموعه وجود نداشته باشد یک خطا گزارش می‌دهد:

    >>> A = {'a', 'b', 'c', 1}
    
    >>> A.remove(1)
    >>> A
    {'c', 'a', 'b'}
    
    >>> A.remove(1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyError: 1
    

    متد مشابه دیگری نیز با الگو (discard(x [اسناد پایتون] وجود دارد که این متد چنانچه x وجود داشته باشد آن را حذف می‌کند؛ بنابرین در صورت نبودن x خطایی گزارش نمی‌گردد:

    >>> A = {'c', 'a', 'b'}
    
    >>> A.discard(1)
    >>> A
    {'b', 'a', 'c'}
    
  • ()pop [اسناد پایتون] - این متد آرگومانی ندارد و به صورت دلخواه یک عضو از مجموعه را حذف و به عنوان خروجی برمی‌گرداند. در مواردی که مجموعه خالی باشد یک خطا گزارش می گردد:

    >>> A = {'a', 'b', 'c'}
    
    >>> A.pop()
    'a'
    
    >>> A.pop()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyError: 'pop from an empty set'
    

frozenset

همانطور که پیش از این بیان شد مجموعه یک شی «تغییر پذیر» است با عضوهای «تغییر ناپذیر» و به دلیل همین تغییر پذیری است که می‌توانیم به سادگی توسط متدها عضوی به آن افزوده یا حذف نماییم. ”frozenset“ یک نوع جدید مجموعه است. همانگونه که می‌توانیم یک شی تاپل را معادل یک شی لیست تغییر ناپذیر تصویر کنیم؛ frozenset را نیز می‌توان یک شی مجموعه تغییر ناپذیر تصور کرد. نوع frozenset همان نوع set است، با تمام ویژگی‌های آن به غیر از تغییر پذیری که با استفاده از کلاس ()frozenset ایجاد می‌گردد:

نسخه‌های 2x:

>>> L = [1, 2, 3]

>>> A = frozenset(L)

>>> type(A)
<type 'frozenset'>

>>> A
frozenset([1, 2, 3])

نسخه‌های 3x:

>>> L =[1, 2, 3]

>>> A = frozenset(L)

>>> type(A)
<class 'frozenset'>

>>> A
frozenset({1, 2, 3})

با استفاده از تابع ()dir می‌توان متوجه متدهای در دسترس شی frozenset شد:

>>> dir(frozenset)    # Python 3.x
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'copy', 'difference', 'intersection', 'isdisjoint', 'issubset', 'issuperset', 'symmetric_difference', 'union']

NoneType

این نوع شی فاقد مقدار است و با انتساب ثابت None [اسناد پایتون] به یک نام ایجاد می‌گردد:

>>> n = None

>>> type(n)
<class 'NoneType'>

>>> print(n)
None

>>> import sys
>>> sys.getsizeof(a)
16

>>> n = 5
>>> type(n)
<class 'int'>

None در پایتون 3x جزو کلمه‌های کلیدی (keywords) تعریف شده است.

دسته‌بندی

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

  • انواع عددی (Numeric Types):

    1
    2
    3
    4
    5
    6
    7
    - int
    - long (2.x)
    - float
    - complex
    - Decimal
    - Fraction
    - bool
    
  • انواع دنباله (Sequence Types):

    1
    2
    3
    4
    5
    6
    - str
    - unicode (2.x)
    - bytes (3.x)
    - bytearray (3.x/2.6+)
    - tuple
    - list
    
  • انواع تغییر ناپذیر (Immutable Types):

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    - int
    - long (2.x)
    - float
    - complex
    - Decimal
    - Fraction
    - bool
    - str
    - unicode (2.x)
    - bytes (3.x)
    - tuple
    - frozenset
    
  • انواع تغییر پذیر (Mutable Types):

    1
    2
    3
    4
    - bytearray (3.x/2.6+)
    - list
    - dict
    - set
    
  • انواع نگاشت (Mapping Types):

    1
    - dict
    
  • انواع مجموعه (Set Types):

    1
    2
    - set
    - frozenset
    
  • برخی دیگر:

    1
    2
    3
    - zip
    - dict_views
    - NoneType
    

در درس‌های بعد نیز با انواع آماده (Built-in) دیگری آشنا خواهیم شد.



😊 امیدوارم مفید بوده باشه

لطفا دیدگاه و سوال‌های مرتبط با این درس خود را در کدرز مطرح نمایید.