برنامه‌نویسی پایتون فهرست مطالب
فصل ۱۴

دیکشنری، تاپل و مجموعه

لیست تنها ظرف پایتون نیست. سه ظرف دیگر هم هست که هر کدام برای کار خاصی ساخته شده‌اند. انتخاب ظرف درست، نصف حل مسئله است.

در این فصل می‌خوانید
  1. دیکشنری چیست
  2. تغییر دادن دیکشنری
  3. متد get و خطای کلید
  4. پیمایش دیکشنری
  5. ساختن دیکشنری از متغیرها
  6. شمارش با دیکشنری
  7. تاپل
  8. باز کردن تاپل
  9. مجموعه
  10. عملیات مجموعه‌ای
  11. کدام ظرف را انتخاب کنیم

۱. دیکشنری چیست

در لیست، هر عضو با شماره پیدا می‌شود. در دیکشنری، هر مقدار با یک کلید پیدا می‌شود. درست مثل فرهنگ لغت که معنی را با کلمه پیدا می‌کنید، نه با شماره صفحه.

# A dictionary stores pairs of "key: value".
# The key is how we find the value again - there are no positions here.
def main() -> None:
    student = {
        'name': 'alireza',
        'age': 20,
        'email': 'alireza@kadoosedu.ir',
    }

    print(student)
    print(student['age'])       # reading by key
    print(student['email'])
    print(student['name'])

    print(len(student))         # number of pairs -> 3
    print('age' in student)     # 'in' looks at the KEYS -> True

if __name__ == '__main__':
    main()

مبانی دیکشنری: نمونه 01_dict_basics.py

{'name': 'alireza', 'age': 20, 'email': 'alireza@kadoosedu.ir'}
20
alireza@kadoosedu.ir
alireza
3
True

شرح مثال

۲. تغییر دادن دیکشنری

# A dictionary is mutable: keys can be added, changed and removed.
def main() -> None:
    student = {'name': 'Ali', 'age': 20}

    student['age'] = 21              # change an existing key
    student['city'] = 'Rasht'        # a key that does not exist is CREATED
    print(student)

    student.update({'age': 22, 'email': 'ali@kadoosedu.ir'})
    print(student)

    removed = student.pop('email')   # remove and return the value
    print('removed:', removed)

    del student['city']              # remove without returning
    print(student)

    student.clear()
    print(student)                   # {}

if __name__ == '__main__':
    main()

تغییر دیکشنری: نمونه 02_dict_modify.py

نکته کلیدی: نوشتن روی کلیدی که وجود ندارد، آن را می‌سازد. این با لیست فرق دارد که در آن lst[10] = 5 روی لیست کوتاه خطا ایجاد می‌کند. همین ویژگی، دیکشنری را برای ساختن تدریجی داده عالی می‌کند.

۳. متد get و خطای کلید

# Reading a key that does not exist with [] raises a KeyError.
def main() -> None:
    student = {'name': 'Ali', 'age': 20}

    # print(student['city'])   ->  KeyError: 'city'

    # get() returns None instead of crashing ...
    print(student.get('city'))              # None

    # ... or a default value that we choose.
    print(student.get('city', 'unknown'))   # 'unknown'

    # The safe pattern with 'in':
    if 'city' in student:
        print(student['city'])
    else:
        print('the key "city" does not exist')

    # setdefault() reads the key, and creates it when it is missing.
    print(student.setdefault('city', 'Rasht'))
    print(student)

if __name__ == '__main__':
    main()

خواندن امن: نمونه 03_dict_get.py

روشوقتی کلید نباشد
d['x']خطای KeyError و توقف برنامه
d.get('x')None برمی‌گرداند
d.get('x', 0)مقدار پیش‌فرض شما را برمی‌گرداند
d.setdefault('x', 0)کلید را با مقدار پیش‌فرض می‌سازد

وقتی داده از کاربر یا از فایل می‌آید، هرگز مطمئن نیستید که کلید وجود دارد. عادت کنید در چنین جاهایی get بنویسید.

۴. پیمایش دیکشنری

def main() -> None:
    student = {
        'name': 'alireza',
        'age': 20,
        'email': 'alireza@kadoosedu.ir',
    }

    # Looping over a dictionary gives the KEYS.
    for key in student:
        print(key, ':', student[key])

    print('---')

    # The three views:
    print(list(student.keys()))     # ['name', 'age', 'email']
    print(list(student.values()))   # ['alireza', 20, 'alireza@kadoosedu.ir']
    print(list(student.items()))    # [('name', 'alireza'), ...]

    print('---')

    # items() gives the key and the value together - the usual way.
    for key, value in student.items():
        print(f'{key} -> {value}')

if __name__ == '__main__':
    main()

پیمایش: نمونه 04_dict_loops.py

شرح مثال

۵. ساختن دیکشنری از متغیرها

# Keys and values can come from variables.
def main() -> None:
    key1 = 'name'
    key2 = 'age'
    key3 = 'city'

    value1 = 'Ali'
    value2 = 25
    value3 = 'Rasht'

    person = {
        key1: value1,
        key2: value2,
        key3: value3,
    }

    print(person)

    # dict() with keyword arguments is another way of building one.
    other = dict(name='Sara', age=19, city='Rasht')
    print(other)

if __name__ == '__main__':
    main()

ساختن از متغیر: نمونه 05_dict_from_variables.py

۶. شمارش با دیکشنری

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

# Counting is the killer application of dictionaries:
# the key is the thing we count, the value is how many times we saw it.
def main() -> None:
    sentence = input('Enter a sentence: ')

    counts: dict[str, int] = {}

    for char in sentence:
        if char == ' ':
            continue
        if char in counts:
            counts[char] += 1
        else:
            counts[char] = 1

    for char, count in counts.items():
        print(f'{char}: {count}')

    # The same loop written with get(), which removes the if/else:
    counts2: dict[str, int] = {}
    for char in sentence.replace(' ', ''):
        counts2[char] = counts2.get(char, 0) + 1

    print(counts2)

if __name__ == '__main__':
    main()

شمارنده: نمونه 06_dict_counter.py

Enter a sentence: hello
{'h': 1, 'e': 1, 'l': 2, 'o': 1}

شرح مثال

۷. تاپل

تاپل مثل لیست است، با یک تفاوت بزرگ: پس از ساخته شدن هرگز تغییر نمی‌کند.

# A tuple is like a list, but it can NEVER be changed after it is created.
def main() -> None:
    my_tuple = (1, 'Hello', 2, 3, True, 3, 3, 4)

    print(my_tuple)
    print(my_tuple[1])         # indexing works
    print(my_tuple[2:5])       # slicing works
    print(len(my_tuple))
    print(my_tuple.count(3))   # 3 appears three times
    print(my_tuple.index(2))

    # my_tuple[0] = 100    ->  TypeError: 'tuple' object does not support
    #                          item assignment

    # A tuple with a single item needs a comma!
    one = (5,)
    not_a_tuple = (5)
    print(type(one), type(not_a_tuple))

    # The parentheses are optional.
    point = 3, 4
    print(point, type(point))

    # Why tuples? They are safe (nobody can modify them by mistake),
    # slightly faster, and they can be used as dictionary keys.
    distances = {(0, 0): 'origin', (3, 4): 'point A'}
    print(distances[(3, 4)])

if __name__ == '__main__':
    main()

تاپل: نمونه 07_tuple_basics.py

تاپل تک‌عضوی حتماً ویرگول می‌خواهد

(5) یک تاپل نیست، فقط عدد ۵ داخل پرانتز است. (5,) تاپل است. آن ویرگول عجیب، تنها چیزی است که این دو را از هم جدا می‌کند و منبع باگ‌های گیج‌کننده است.

سه دلیل وجود تاپل:

۸. باز کردن تاپل

def min_max(numbers: list[int]) -> tuple[int, int]:
    'Return the smallest and the biggest number - two values in one tuple.'
    return min(numbers), max(numbers)

def main() -> None:
    my_list = [3, 77, -6, 14, 31]

    # Unpacking: the two returned values land in two variables.
    low, high = min_max(my_list)
    print(f'Min: {low}, Max: {high}')

    # Unpacking works on any sequence.
    a, b, c = (1, 2, 3)
    print(a, b, c)

    x, y, z = [10, 20, 30]
    print(x, y, z)

    # The classic swap - no temporary variable needed.
    x, y = y, x
    print(x, y)

    # '*' collects "the rest".
    first, *others = [1, 2, 3, 4, 5]
    print(first, others)

if __name__ == '__main__':
    main()

باز کردن: نمونه 08_tuple_unpacking.py

شرح مثال

۹. مجموعه

مجموعه ظرفی است که عضو تکراری ندارد و ترتیب هم ندارد.

# A set holds only UNIQUE values, and it has no order.
def main() -> None:
    my_set = {1, 1, 5, 3, 3, 3, 3, 7, 7}
    print(my_set)                  # {1, 3, 5, 7} - the duplicates are gone

    for item in my_set:
        print(item, end=' ')
    print()

    my_set.add(10)                 # add one item
    my_set.discard(1)              # remove, and stay silent when it is missing
    # my_set.remove(99)            # remove, but raise KeyError when missing
    print(my_set)

    print(5 in my_set)             # membership test - very fast on a set

    # The most common use: removing the duplicates of a list.
    numbers = [1, 2, 3, 3, 4, 5, 5, 5]
    unique = list(set(numbers))
    print(unique)

    # Careful: a set has no order, so sort it if the order matters.
    print(sorted(set(numbers)))

    # An empty set must be created with set(); {} is an empty DICTIONARY.
    empty_set = set()
    empty_dict = {}
    print(type(empty_set), type(empty_dict))

if __name__ == '__main__':
    main()

مجموعه: نمونه 09_set_basics.py

شرح مثال

۱۰. عملیات مجموعه‌ای

# Sets support the operations of mathematical set theory.
def main() -> None:
    python_students = {'Ali', 'Sara', 'Reza', 'Maryam'}
    linux_students = {'Reza', 'Maryam', 'Omid'}

    print('union       :', python_students | linux_students)
    print('intersection:', python_students & linux_students)
    print('difference  :', python_students - linux_students)
    print('symmetric   :', python_students ^ linux_students)

    # The same operations have method names too.
    print(python_students.union(linux_students))
    print(python_students.intersection(linux_students))
    print(python_students.difference(linux_students))

    print(linux_students.issubset(python_students))   # False

if __name__ == '__main__':
    main()

عملیات مجموعه‌ای: نمونه 10_set_operations.py

عملگرنامیعنی
|اجتماعهر که در یکی از دو مجموعه هست
&اشتراکفقط کسانی که در هر دو هستند
-تفاضلکسانی که در اولی هستند و در دومی نیستند
^تفاضل متقارنکسانی که فقط در یکی هستند

این عملیات‌ها در کار واقعی خیلی به کار می‌آیند: «کدام کاربرها هر دو دوره را ثبت‌نام کرده‌اند»، «کدام فایل‌ها در پوشه اول هستند و در دومی نیستند». نوشتنشان با حلقه ده خط طول می‌کشد و با مجموعه یک خط.

۱۱. کدام ظرف را انتخاب کنیم

'''Which container should I use?

    list  [ ]   ordered, changeable, duplicates allowed
                -> a sequence of things you will add to and loop over
    tuple ( )   ordered, NOT changeable, duplicates allowed
                -> a fixed record, several return values, a dictionary key
    set   { }   NOT ordered, changeable, NO duplicates
                -> membership tests, removing duplicates
    dict  {k:v} keys -> values
                -> when every item has a name / an identifier
'''

def main() -> None:
    scores_list = [20, 18, 20, 15]                 # order matters
    student_record = ('Ali', 'Rezaei', 2005)       # fixed, never changes
    subjects = {'math', 'physics', 'math'}         # duplicates disappear
    student = {'name': 'Ali', 'score': 20}         # named fields

    print(scores_list, student_record, subjects, student)

if __name__ == '__main__':
    main()

مقایسه: نمونه 11_which_container.py

ظرفنشانهمرتبتغییرپذیرتکراریکجا
لیست[ ]بلهبلهبلهدنباله‌ای که به آن اضافه می‌کنید
تاپل( )بلهخیربلهرکورد ثابت، چند خروجی تابع
مجموعه{ }خیربلهخیرحذف تکراری، بررسی عضویت
دیکشنری{k: v}بلهبلهکلید یکتاوقتی هر داده یک نام دارد
فایل‌های تمرینی این فصل

پوشه S14-dict-tuple-set شامل نمونه‌های 01_dict_basics.py تا 11_which_container.py.

خلاصه فصل

ابزاروظیفه آن
{'k': v}ساختن دیکشنری
d['k']خواندن با کلید. اگر نباشد خطا
d.get('k', default)خواندن امن با مقدار پیش‌فرض
d.items()کلید و مقدار با هم، برای حلقه
d[k] = d.get(k, 0) + 1اصطلاح استاندارد شمارش
(a, b)تاپل. تغییرناپذیر. تک‌عضوی: (a,)
a, b = func()باز کردن چند خروجی
x, y = y, xجابه‌جایی در یک خط
set(lst)حذف تکراری‌ها
& | - ^اشتراک، اجتماع، تفاضل، تفاضل متقارن
set() در برابر {}اولی مجموعه خالی، دومی دیکشنری خالی

تمرین‌های فصل چهارده

  1. دیکشنری یک دانشجو بسازید (نام، سن، شهر) و کلید به کلید چاپش کنید.
  2. یک جمله بگیرید و بشمارید هر کلمه چند بار تکرار شده است.
  3. یک دفترچه تلفن بسازید: افزودن مخاطب، جست‌وجو، حذف و نمایش همه.
  4. دو لیست عدد بگیرید و با مجموعه، عددهایی که در هر دو هستند را چاپ کنید.
  5. یک جمله بگیرید و مجموعه حروف متمایزش را مرتب‌شده چاپ کنید.
  6. تابع min_max_avg(numbers) را بنویسید که سه مقدار را در یک تاپل برگرداند.
  7. دیکشنری {درس: نمره} بسازید و درسی که بهترین نمره را دارد چاپ کنید.
  8. توضیح دهید فرق {} با set() چیست.
فصل قبل: توابع پیشرفته فصل بعد: ساختارهای داده تودرتو