1.2.35 · D3 · Coding › Introduction to Programming (Python) › Dictionary and set comprehensions
Parent note ne tumhe machine sikhaya tha: braces {}, dict ke liye colon :, sets ke liye no colon,
peeche ek for, aur optional if. Yeh page crash-test lab hai. Hum har tarah ki situation list karenge
jisme dict/set comprehension use ho sakti hai — weird keys, collisions, empty inputs, nested loops, filters,
ternaries — aur phir har ek ko work out karenge jab tak tumne khud result dekh nahi liya. Jab tum finish karo,
koi bhi exam question tumhe ek aisi shape nahi dikha payega jo tumne pehle nahi dekhi.
Yeh page sirf wahi assume karta hai jo parent note
ne build kiya. Agar koi term naya lagta hai, use yahan dobara earn kiya jayega.
Definition Teen roz ke tools jo hum use karte hain — yahan dobara earn kiye
range(a, b) a se shuru hokar b se theek pehle tak ke whole numbers produce karta hai.
Toh range(1, 5) hai 1, 2, 3, 4 (right end exclude hota hai — ungli pe gino: chaar numbers).
Yeh simply ek machine hai jo consecutive integers deta hai, ek per loop pass.
x % 3 (padho "x mod 3") wo remainder hai jo x ko 3 se divide karne ke baad bachta hai. Socho
x cookies ko 3-3 ki rows mein rakh rahe ho: % hai kitni bachi jo ek row nahi bhar payi. Toh 7 % 3 == 1,
6 % 3 == 0, 2 % 3 == 2. Mod 3 remainders sirf 0, 1, ya 2 ho sakte hain — isliye yeh baad mein
key collisions cause karega (sirf 3 possible keys hain).
n ** 2 aur n ** 3 — ** Python ka power (exponent) operator hai, do
multiplications nahi . n ** 2 matlab "n times itself" = n 2 (square); n ** 3 matlab
"n times itself three times" = n 3 (cube). Toh 4 ** 3 hai 4 × 4 × 4 = 64 . Do stars ko
ek chota raised exponent samjho.
Definition "Hashable" — woh property jo ek dict key mein honi chahiye
Key store karne ke liye, ek dict use ek hash function se guzaarta hai: ek machine jo key ko ek fixed
number (uska slot address ) mein badal deti hai, taaki lookups instant hon. Ek value hashable hoti hai jab (1) use
us machine ko diya ja sake aur (2) uska hash poori zindagi kabhi change na ho. Immutable cheezein —
numbers, strings, aur unke tuples — qualify karti hain, kyunki yeh kabhi change nahi ho sakti. Mutable cheezein —
lists, sets, dicts — nahi karte, kyunki agar file hone ke baad change ho jayein, toh dict unhe dobara dhundh nahi sakti.
Toh: ek dict key (aur ek set element) hashable honi chahiye. Dekho Hashing and hashable types .
Intuition Dicts apna insertion order yaad rakhte hain (Python 3.7+)
Python 3.7 ke baad se, ek dict keys ko us order mein rakhta hai jisme woh pehli baar insert hui thi . Toh jab hum
colliding key ke liye "last write wins" kehte hain, toh value update hoti hai lekin key apni original
slot mein rehti hai — woh end mein nahi jaati. Yeh tab matter karta hai jab tum ek comprehension ke output ka printed order predict karo.
Har comprehension question actually is table ki ek row hai. Har cell ek alag behaviour hai
jise tumhe sight par predict kar paana chahiye.
#
Case class
Kya mushkil banata hai isse
Example jo isko hit karta hai
A
Basic dict, unique keys
kuch nahi — yeh baseline hai
Ex 1
B
Key collision (do items, same key)
baad wali value overwrite karti hai
Ex 2
C
Collision fixed by grouping into lists
sab kuch rakho
Ex 3
D
Filter if at the end
kuch items koi entry produce nahi karte
Ex 4
E
Ternary if/else in the value
har item entered, value chosen
Ex 5
F
Set comprehension, duplicate values dropped
count shrinks
Ex 6
G
Empty / degenerate input
empty iterable, {} trap
Ex 7
H
Nested comprehension (do fors)
Cartesian sweep
Ex 8
I
Unhashable key — crash ka case
list key nahi ban sakti
Ex 9
J
Real-world word problem + exam twist
syntax mein intent padhna
Ex 10
K
Chained filters (if cond1 if cond2)
dono pass hone chahiye
Ex 11
Intuition Comprehension ko zor se kaise padhen
Pehle hamesha right-to-left English mein translate karo: for clause padho ("for each item…"),
phir koi bhi if ("…but only when…"), phir head ("…build this pair / value"). Kuch bhi
predict karne se pehle yahi karo.
Neeche Figure s01 dekho: yeh ek comprehension ke teen parts ko exact us order mein label karta hai jisme
tumhe padhne chahiye — black arrows for (part 1) aur if (part 2) ki taraf point karte hain, aur red
arrow colon wale head (part 3) ko highlight karta hai, woh piece jo dict-vs-set decide karta hai. Koi bhi real code padhne se pehle numbered order mein arrows trace karo.
Statement. Ek dict banao jo har number 1..4 ko uske cube se map kare.
{n: n ** 3 for n in range ( 1 , 5 )}
Forecast: kitni entries hongi, aur key 3 par value kya hai? Aage padhne se pehle guess karo.
for padho. range(1, 5) yields 1, 2, 3, 4 — chaar items (yaad rakho: right end 5
exclude hota hai).
Yeh step kyun? Distinct keys ki number kabhi bhi items ki number se zyada nahi ho sakti; source ko pehle count karna answer bound kar deta hai.
Har pair build karo. Har n ke liye, head hai n : n**3 (yaad rakho ** power operator hai, toh
n**3 hai n 3 , cube). Toh 1:1, 2:8, 3:27, 4:64.
Yeh step kyun? Head literally wahi hai jo hum store karte hain — colon ke left mein key, right mein value.
Saare keys 1,2,3,4 distinct hain , toh koi overwriting nahi hoti.
Yeh step kyun? Cell A woh case hai jahan kuch collide nahi hota — reference behaviour establish karta hai.
Result: {1: 1, 2: 8, 3: 27, 4: 64} — 4 entries, 3 par value hai 27.
Verify: 4**3 == 64 aur exactly 4 keys hain. ✅
Statement. ```python
{x % 3: x for x in range(6)}
**Forecast:** tum 6 entries expect kar sakte ho. Actually kitni bachti hain?
1. **Order mein (key, value) pairs list karo.** `x=0→(0,0)`, `1→(1,1)`, `2→(2,2)`, `3→(0,3)`, `4→(1,4)`, `5→(2,5)`.
*Yeh step kyun?* Order yahan matter karta hai — ek dict pairs ko left to right process karta hai, aur repeated key
**earlier value ko replace** kar deta hai. (Yaad rakho `x % 3` sirf `0, 1, 2` ho sakta hai, toh keys *zaroor* repeat hongi.)
2. **Key ke hisaab se group karo.** Key `0` aata hai `x=0` ke liye phir `x=3`; key `1` `x=1` ke liye phir `x=4`; key `2` `x=2` ke liye phir `x=5`.
*Yeh step kyun?* Ek dict har key ko **ek baar** hold kar sakta hai. Duplicates dekhna batata hai kaun si values khatam hogi.
3. **"Last write wins" apply karo.** Key `0`→`3`, key `1`→`4`, key `2`→`5`. Insertion order ki wajah se,
keys `0, 1, 2` print hongi (unka first-seen order), chahe *values* baad ke items se aayi hon.
*Yeh step kyun?* Comprehension `d[k]=v` karne wale loop ke equivalent hai; har key ka final assignment
wahi rehta hai, lekin key ki *position* pehli insertion par fix ho jaati hai.
**Result:** `{0: 3, 1: 4, 2: 5}` — sirf 3 entries.
**Verify:** `3 % 3 == 0`, `4 % 3 == 1`, `5 % 3 == 2`, aur length hai `3`. ✅
Neeche Figure s02 dekho: top par chhe input boxes (x=0..5) teen key buckets mein fan down hote hain.
Chhe thin black arrows land karte, lekin sirf red arrows — har bucket mein last write — bachte hain,
aur buckets ke neeche red -> 3 / -> 4 / -> 5 final stored value hai. Yeh picture
wahi hai "last write wins" rule visible banaya hua.
defaultdict kya hota hai?
Ek normal dict error raise karta hai agar tum koi aisi key touch karo jo abhi exist nahi karti: d[k].append(x) fail
hota hai kyunki d[k] wahan hai hi nahi. Ek defaultdict(list) (collections module se) ek aisa dict hai jo,
pehli baar jab tum missing key touch karo, auto-create kar deta hai ek empty list [] — toh
d[k].append(x) bas kaam karta hai. Socho yeh ek aisa dict hai jo tumhe ek fresh empty box de deta hai jis moment
tum ek empty shelf tak pahuncho. Baaki sab normal dict jaisa hi hai.
Statement. range(6) se, numbers ko unke remainder mod 3 ke basis par group karo, sab ko rakhte hue .
Ek line wali comprehension ek list in-place grow nahi kar sakti, toh hum do-step pattern use karte hain:
from collections import defaultdict
groups = defaultdict( list )
for x in range ( 6 ):
groups[x % 3 ].append(x)
result = {k: v for k, v in groups.items()}
Forecast: key 0 ke neeche kya list hai?
Pure comprehension kyun nahi? Ek dict comprehension ek key per ek value evaluate karta hai; woh
accumulate nahi kar sakta. Toh hum loop mein accumulate karte hain (ek defaultdict use karke taaki empty list auto-create ho),
phir ek comprehension ke saath dict mein snapshot lete hain.
(Yahan "snapshot" ka matlab hai: jab loop groups fill karna khatam kar le, tab hum uske current key→list
contents ki ek fresh copy ek naye dict mein lete hain — ek still photo, koi live link nahi.)
Yeh step kyun? Yeh tool ki limit dikhata hai — cell B data lose karta hai, cell C use bachata hai value type ko
number se list mein change karke.
Append trace karo. Key 0 collect karta hai x=0,3; key 1 collect karta hai 1,4; key 2 collect karta hai 2,5.
Yeh step kyun? .append existing list ko grow karta hai replace karne ki jagah — "last write wins" ka opposite.
Plain dict mein snapshot lo. {k: v for k, v in groups.items()} har key ko uski poori list ke saath copy karta hai.
Yeh step kyun? .items() (key, value) pairs yield karta hai; hum k, v unpack karte hain aur ek clean dict rebuild karte hain.
Result: {0: [0, 3], 1: [1, 4], 2: [2, 5]}.
Verify: har original number 0..5 lists mein exactly ek baar appear karta hai (total length 6). ✅
Statement. Har number 1..10 ko uske square se map karo, lekin sirf 3 ke multiples .
{n: n ** 2 for n in range ( 1 , 11 ) if n % 3 == 0 }
Forecast: kaunse keys filter survive karte hain?
if pair build hone se pehle run karta hai. Har n ke liye, poocho n % 3 == 0? (yaani kya n
3 se evenly divide hota hai, remainder 0 chhod ke?) Agar false, toh woh n koi entry produce nahi karta .
Yeh step kyun? Trailing if ek gate hai, value-chooser nahi — yeh decide karta hai kya koi item
enter karega, nahi kya woh ban jaayega.
Survivors: 3, 6, 9.
Yeh step kyun? Yeh sirf wahi n hain 1..10 mein jinka remainder 0 mod 3 hai.
Sirf survivors ke liye pairs build karo: 3:9, 6:36, 9:81 (n**2, yaani square use karke).
Yeh step kyun? Head sirf unhi items ke liye evaluate hota hai jo gate pass kar chuke hain .
Result: {3: 9, 6: 36, 9: 81}.
Verify: 3**2==9, 6**2==36, 9**2==81, length 3. ✅
Statement. Har number 0..4 ko "even" ya "odd" label karo.
{n: ( "even" if n % 2 == 0 else "odd" ) for n in range ( 5 )}
Forecast: is baar kitni entries — input ke barabar, ya kam?
Koi trailing if nahi, toh kuch filter out nahi hota. 5 items mein se har ek entry produce karta hai.
Yeh step kyun? Yeh Example 4 se key contrast hai: filter removes items; ternary
sab ko rakhta hai aur sirf value change karta hai . (Dekho Ternary conditional expression .)
Har item ke liye ternary evaluate karo. n=0→"even", 1→"odd", 2→"even", 3→"odd", 4→"even"
(n % 2 == 0 use karke = "2 se divide karne par remainder 0" = even).
Yeh step kyun? Ternary A if cond else B ek value pick karta hai; woh value expression ke andar rehta hai,
front mein, clarity ke liye parentheses mein wrapped.
Assemble karo. Saare 5 keys 0..4 distinct hain — koi collision nahi.
Yeh step kyun? Confirm karta hai ki entry count input count (5) ke barabar hai, filtered case se alag.
Result: {0: 'even', 1: 'odd', 2: 'even', 3: 'odd', 4: 'even'} — 5 entries.
Verify: exactly 3 keys "even" pe map karte hain (keys 0,2,4) aur 2 "odd" pe. ✅
Common mistake Filter vs chooser — classic mix-up
{... for n in ... if cond} items drop karta hai (end mein gate).
{... : (A if cond else B) for n in ...} saare items rakhta hai (front mein chooser).
Poocho: "kya mujhe kam items chahiye, ya same items with different values?"
Statement. Words ki list se distinct string lengths ek set mein collect karo.
words = [ "hi" , "cat" , "dog" , "sun" , "elephant" ]
{ len (w) for w in words}
Forecast: list mein 5 words hain — resulting set mein kitne elements?
Koi colon nahi ⇒ yeh ek set hai (dekho Sets in Python ). Har item ek value yield karta hai, pair nahi.
Set elements, dict keys ki tarah, hashable hone chahiye (numbers qualify karte hain).
Yeh step kyun? Set-vs-dict pehchanna step zero hai; : ki absence yeh decide karti hai. (Input
words ek list hai; output ek set hai — dono ko confuse mat karo.)
Har length compute karo: "hi"→2, "cat"→3, "dog"→3, "sun"→3, "elephant"→8.
Yeh step kyun? Hume kya collide karta hai dekhne ke liye dedup se pehle raw values chahiye.
Duplicates drop karo. Value 3 teen baar produce hui; set use ek baar rakhta hai.
Yeh step kyun? Yahi reason hai set choose karne ka — automatic uniqueness, powered by
hashing .
Result: {2, 3, 8} — 5 words se 3 elements.
Verify: set ki length 3 hai aur {2, 3, 8} ke barabar hai. ✅
Statement. Har ek predict karo:
{k: v for k, v in []} # (a) empty source
{x for x in []} # (b) empty set comp
type ({}) # (c) the empty-braces trap
type ( set ()) # (d) how to get a real empty set
Forecast: (a)–(d) mein se kaun dict hai aur kaun set?
(a) Empty iterable → comprehension ke type ka empty result. Koi items nahi matlab koi pairs nahi,
lekin shape abhi bhi ek dict comprehension hai (iske paas colon hai), toh tum {} paate ho — ek empty dict.
Yeh step kyun? Type syntax se fix hota hai, is baat se nahi ki koi item run hua ya nahi.
(b) Empty set comprehension → ek empty set , print hota hai set() ke roop mein.
Yeh step kyun? Koi colon nahi ⇒ set, zero items ke saath bhi.
(c) Akela {} ek empty dict hai. Braces historically pehle dicts ke the.
Yeh step kyun? Yeh sabse common beginner trap hai — braces set-ish lagte hain .
(d) set() empty set literal likhne ka eklauta tarika hai.
Yeh step kyun? "Empty set" ke liye koi colon-free brace form nahi hai, isliye constructor zaroori hai.
Results: (a) {} dict, (b) set(), (c) dict, (d) set.
Verify: type({}) is dict aur type(set()) is set aur (a) mein empty comprehension ki length 0 hai. ✅
Statement. Ek multiplication lookup build karo: i ke liye 1..3 aur j ke liye 1..3,
tuple (i, j) ko product i*j se map karo.
{(i, j): i * j for i in range ( 1 , 4 ) for j in range ( 1 , 4 )}
Forecast: kitne keys — aur key tuple kyun hai?
Do fors ko left-to-right padho = outer phir inner. Pehla for i outer hai; for j
inner hai. Yeh poora 3×3 grid sweep karta hai.
Yeh step kyun? Comprehension mein nested fors nested loops ki tarah run karte hain — outer slow, inner fast.
Cells count karo. i ki 3 values × j ki 3 values = 9 pairs, saari distinct.
Yeh step kyun? Koi collision nahi kyunki har (i, j) combination unique hai.
Tuple key kyun? (i, j) pair hashable hai (yeh immutable hai — iske contents kabhi change nahi ho sakte),
toh woh dict key ban sakta hai; list [i, j] nahi ban sakti, kyunki lists mutable hain aur isliye
unhashable hain (yeh Example 9 ka preview hai).
Yeh step kyun? Keys hashable honi chahiye — tuples qualify karte hain, lists nahi. (Upar "Hashable" definition dekho.)
Result: 9 entries, e.g. {(1,1):1, (1,2):2, ..., (3,3):9}; (2, 3) par value 6 hai.
Verify: length 9 hai aur key (2, 3) par value 6 hai. ✅
Neeche Figure s03 dekho: 3×3 grid har (i, j) combination ko ek dot ke roop mein dikhata hai, saath mein choti si
product i*j likhi hui — i vertical axis par chadhta hai (outer loop), j horizontal par chalta hai
(inner loop). Red dot key (2, 3) mark karta hai, jiska stored value 6 hai, toh tum dekh sakte ho
ki nested fors ek rectangle of keys enumerate karte hain.
Statement. Left crash kyun karta hai aur right succeed kyun karta hai?
{[i] : i for i in range ( 3 )} # ✗ TypeError: unhashable type: 'list'
{(i,): i for i in range ( 3 )} # ✓ works
Forecast: ek valid key mein honi chahiye aisi property ko describe karne wala ek word kya hai?
Ek dict keys ko unke hash ke basis par store karta hai. Key place karne ke liye, Python hash(key) call karta hai; lists
hash hone se mana karti hain kyunki woh change ho sakti hain (yaad karo "Hashable" definition — mutable cheezein hash nahi ho sakti).
Yeh step kyun? Crash comprehensions ke baare mein bilkul nahi hai — yeh underlying dict rule hai.
[i] ek list hai ⇒ unhashable ⇒ TypeError jis moment pehla pair build hota hai.
Yeh step kyun? Ek bhi kharab key poori comprehension abort kar deti hai.
(i,) ek one-element tuple hai ⇒ immutable ⇒ hashable ⇒ fine.
Yeh step kyun? Trailing comma ise tuple banata hai, parenthesised value nahi; immutability hi
ise hash karne deti hai. (Dekho Hashing and hashable types .)
Result: left TypeError raise karta hai; right yields {(0,): 0, (1,): 1, (2,): 2}.
Verify: tuple-key version ki length 3 hai aur key (2,) par value 2 hai; list genuinely
hashable nahi hai. ✅
"Agar woh change ho sakta hai, woh key nahi ban sakta." Lists, sets, dicts change hote hain → no. Numbers, strings,
tuples-of-those nahi hote → yes.
Statement (word problem). Ek shop ki inventory hai stock = {"pen": 0, "ink": 12, "pad": 3, "cap": 0}.
Un products ke names ka ek set build karo jo out of stock hain, phir sirf in-stock
products ka ek dict banao jo name → quantity map kare.
stock = { "pen" : 0 , "ink" : 12 , "pad" : 3 , "cap" : 0 }
out_of_stock = {name for name, qty in stock.items() if qty == 0 }
in_stock = {name: qty for name, qty in stock.items() if qty > 0 }
Forecast: kaun se names har collection mein aate hain?
Intent translate karo. "Out of stock wale names" → hume sirf names chahiye, koi pairing nahi →
filter qty == 0 ke saath ek set .
Yeh step kyun? Set vs dict choose karna is baat se aata hai ki question tumse kya rakhne ko keh raha hai .
.items() (name, qty) deta hai; unpack karo aur gate lagao. out_of_stock mein "pen", "cap" aate hain.
Yeh step kyun? Filter value name emit hone se pehle run karta hai — sirf zero-quantity names pass karte hain.
In-stock ko name→qty chahiye , toh yeh ek dict hai filter qty > 0 ke saath: {"ink": 12, "pad": 3}.
Yeh step kyun? Yahan hum quantity yaad rakhna chahte hain, toh ek pair (colon!) zaroori hai.
Insertion order ki wajah se, "ink" "pad" se pehle print hota hai (original stock mein unka order).
Exam twist. "Tum out_of_stock ko {name: 0 for ...} mein kaise badloge?" — set (koi colon nahi) ko
constant value 0 wale dict se swap karo:
{name: 0 for name, qty in stock.items() if qty == 0 }
# {'pen': 0, 'cap': 0}
Lesson: "names ka set" se "names → 0 ka dict" mein jaane ke liye sirf colon add karna kaafi hai.
Results: out_of_stock == {"pen", "cap"}; in_stock == {"ink": 12, "pad": 3}; twist deta hai
{"pen": 0, "cap": 0}.
Verify: out_of_stock mein 2 elements hain; in_stock mein 2 entries hain aur in_stock["ink"] == 12; twisted
dict {"pen": 0, "cap": 0} ke barabar hai. ✅
Statement (exam twist). 1..30 se woh numbers rakho jo both even aur 3 ke multiples hain,
har ek ko uske half se map karte hue.
{n: n // 2 for n in range ( 1 , 31 ) if n % 2 == 0 if n % 3 == 0 }
Forecast: do ifs ek saath — kya yeh "or" hai ya "and"? Kaun se keys bachte hain?
Back-to-back likhe do ifs matlab AND, OR nahi. Ek item ko n % 2 == 0 aur phir
n % 3 == 0 pass karna hoga; kisi ek mein fail karne par woh drop ho jaata hai. Yeh ek pipe mein stacked gates jaisa lagta hai.
Yeh step kyun? Beginners aksar assume karte hain ki doosra if selection widen karta hai; actually woh use
narrow karta hai — har filter sirf zyada items remove kar sakta hai.
Pehla gate (even): 2, 4, 6, …, 30. Doosra gate (mult of 3): unme se, rakho 6, 12, 18, 24, 30.
Yeh step kyun? Even aur 3 ka multiple hona 6 ka multiple hone ke barabar hai, toh
survivors exactly 30 tak ke 6 ke multiples hain.
n // 2 integer division hai — half karta hai aur koi fractional part phenk deta hai. Halves: 6→3,
12→6, 18→9, 24→12, 30→15.
Yeh step kyun? Saare survivors even hain, toh // 2 yahan exact hai; head key → half build karta hai.
Result: {6: 3, 12: 6, 18: 9, 24: 12, 30: 15} — 5 entries.
Verify: saare 5 keys 6 ke multiples hain, length 5 hai, aur 30 // 2 == 15. ✅
ifs = AND, aur ek filter kabhi bhi items add nahi kar sakta
... for n in ... if A if B sirf woh items rakhta hai jahan dono A aur B true hon. Agar tum actually
"A or B" chahte the, tumhe ek combined condition if A or B chahiye, do alag ifs nahi.
Recall Active recall — answers chhupa lo
{x % 3: x for x in range(6)} kitni entries produce karta hai? ::: 3 — keys 0,1,2, har ek apni last value 3,4,5 ke saath
Woh keys kis order mein print honti hain, aur kyun? ::: 0, 1, 2 — unka first-insertion order (dicts Python 3.7 ke baad se insertion order preserve karte hain)
Overwrite karne ki jagah saare colliding items kaise rakhe jaayein? ::: List values mein accumulate karo (e.g. defaultdict(list)), phir dict mein snapshot lo
Trailing if vs value-ternary — kaun items drop karta hai? ::: Trailing if items drop karta hai; ternary sab rakhta hai aur sirf values change karta hai
{len(w) for w in ["hi","cat","dog"]} kya deta hai? ::: {2, 3} — duplicate length 3 collapse ho jaata hai
{k: v for k, v in []} kya return karta hai, aur kis type ka? ::: {}, ek empty dict (syntax mein colon hai)
{[i]: i for i in range(3)} crash kyun karta hai? ::: Ek list unhashable hai (mutable), toh woh dict key nahi ban sakti
Ek comprehension mein back-to-back do ifs ka matlab kya hai? ::: AND — ek item ko dono conditions pass karni hongi
Names-ka-set ko names→0-ka-dict mein badalne ke liye kya single edit chahiye? ::: Colon aur ek value add karo: {name: 0 for ...}
Python mein ** ka matlab kya hai? ::: Power (exponent) operator — n**2 hai n 2 , n**3 hai n 3
Parent: Dictionary and set comprehensions — woh core rules jinhe yeh page stress-test karta hai
List comprehensions — same syntax family with []
Dictionaries in Python — collision / last-write-wins behaviour aur insertion order
Sets in Python — Example 6 mein automatic uniqueness
Generator expressions — lazy (...) cousin, koi collision handling nahi kyunki kuch store nahi hota
Hashing and hashable types — kyun Example 9 crash karta hai aur "hashable" ka matlab kya hai
Ternary conditional expression — Example 5 mein value-chooser