دیکشنری، تاپل و مجموعه
لیست تنها ظرف پایتون نیست. سه ظرف دیگر هم هست که هر کدام برای کار خاصی ساخته شدهاند. انتخاب ظرف درست، نصف حل مسئله است.
۱. دیکشنری چیست
در لیست، هر عضو با شماره پیدا میشود. در دیکشنری، هر مقدار با یک کلید پیدا میشود. درست مثل فرهنگ لغت که معنی را با کلمه پیدا میکنید، نه با شماره صفحه.
# 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
شرح مثال
- دیکشنری با آکولاد نوشته میشود و هر جفت به شکل
کلید: مقداراست. - خواندن با کروشه انجام میشود، ولی داخل کروشه به جای شماره، کلید میگذارید.
- کلیدها معمولاً رشتهاند ولی میتوانند عدد یا تاپل هم باشند. کلید باید تغییرناپذیر باشد، پس لیست نمیتواند کلید باشد.
- عملگر
inروی دیکشنری، کلیدها را بررسی میکند، نه مقدارها. - مقایسه با لیست: اگر بخواهید سن دانشجو را در لیست نگه دارید، باید به خاطر داشته باشید که سن عضو شماره یک است. با دیکشنری فقط مینویسید
student['age']و شش ماه بعد هم میفهمید.
۲. تغییر دادن دیکشنری
# 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()کلیدها،values()مقدارها وitems()جفتها را میدهد.- روش استاندارد و پایتونی، همان
for key, value in d.items()است. آن دو متغیر، همان باز کردن تاپلی است که چند بخش بعد میبینید. - از پایتون ۳٫۷ به بعد، دیکشنری ترتیب درج را حفظ میکند. یعنی همان ترتیبی که کلیدها را اضافه کردهاید، در پیمایش هم دیده میشود.
۵. ساختن دیکشنری از متغیرها
# 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}
شرح مثال
- منطق ساده است: اگر کلید هست یکی زیاد کن، اگر نیست با مقدار یک بسازش.
- نسخه دوم همان کار را با
getو در یک خط انجام میدهد:counts[c] = counts.get(c, 0) + 1. این اصطلاح را حفظ کنید، چون بارها لازمتان میشود. - در فصل بعد ابزار
Counterرا میبینید که همین کار را در یک خط و بدون حلقه انجام میدهد.
۷. تاپل
تاپل مثل لیست است، با یک تفاوت بزرگ: پس از ساخته شدن هرگز تغییر نمیکند.
# 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
شرح مثال
- تابع
min_maxدو مقدار برمیگرداند. در عمل یک تاپل برمیگرداند، ولی چون پرانتز اختیاری است، به نظر میرسد دو چیز است. - باز کردن یعنی اعضای یک دنباله را در چند متغیر بریزیم. تعداد متغیرها باید دقیقاً با تعداد اعضا برابر باشد، وگرنه خطا میگیرید.
- جابهجا کردن دو متغیر در پایتون یک خط است:
x, y = y, x. در زبانهای دیگر به متغیر موقت نیاز دارید. - ستاره «بقیه» را جمع میکند:
first, *others = [1,2,3,4,5]یعنی اولی جدا و بقیه در یک لیست. - در فصل بیست و پنجم این ابزار را کاملتر میبینیم.
۹. مجموعه
مجموعه ظرفی است که عضو تکراری ندارد و ترتیب هم ندارد.
# 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
شرح مثال
- تکراریها به طور خودکار حذف میشوند. پرکاربردترین کاربرد مجموعه همین است:
list(set(numbers)). - مجموعه ترتیب ندارد، پس نمیشود اندیس گرفت. اگر ترتیب مهم است، خروجی را
sortedکنید. - بررسی عضویت با
inروی مجموعه بسیار سریعتر از لیست است. برای لیست میلیونی، این تفاوت بین چند دقیقه و چند میلیثانیه است. discardاگر عضو نباشد ساکت میماند،removeخطا ایجاد میکند.- دام:
{}دیکشنری خالی است، نه مجموعه خالی. برای مجموعه خالی بایدset()بنویسید.
۱۰. عملیات مجموعهای
# 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() در برابر {} | اولی مجموعه خالی، دومی دیکشنری خالی |
تمرینهای فصل چهارده
- دیکشنری یک دانشجو بسازید (نام، سن، شهر) و کلید به کلید چاپش کنید.
- یک جمله بگیرید و بشمارید هر کلمه چند بار تکرار شده است.
- یک دفترچه تلفن بسازید: افزودن مخاطب، جستوجو، حذف و نمایش همه.
- دو لیست عدد بگیرید و با مجموعه، عددهایی که در هر دو هستند را چاپ کنید.
- یک جمله بگیرید و مجموعه حروف متمایزش را مرتبشده چاپ کنید.
- تابع
min_max_avg(numbers)را بنویسید که سه مقدار را در یک تاپل برگرداند. - دیکشنری
{درس: نمره}بسازید و درسی که بهترین نمره را دارد چاپ کنید. - توضیح دهید فرق
{}باset()چیست.