Python Dictionaries

Dictionaries are unordered collections of key-value pairs. Use curly braces {} with key: value format. Keys should be immutable (e.g., strings, numbers, tuples), while values can be of any data type.

1. Creating Dictionaries

my_dict = {} # Empty dictionary.
my_dict = {"name": "Shaista", "age": 30} # Dictionary with string keys.
my_dict = {1:"Python", 2: "Java"} #dictionary with numeric/integer type key
my_dict = dict([('name',"Anam"), ("age",40)]) # Creating using dict()
mix_key_dict = {(1,2):"Tuple", 1: "integer", "name":"string"} # you can make mix of tuple,int or string as a key but value can be any data type

2. Accessing Dictionary Items:

Access value through its key inside square brackets `[]` : value= my_dict[key]. If key is missing KeyError. `value=my_dict.get(key)` can be used also. The get method will return None if a key isn't present vs raising that prior KeyError

person = {"name": "Noorain", "age": 24,"city": "New York"}
name = person["name"]
print(name) #Arshiya
age=person.get("age")
print(age) #24
#Accessing an invalid key
#print(person['location']) # If key not present ,KeyError thrown

3. Adding and Modifying items:

student = {"name":"Noorain","age": 24}
# Add/insert item (by direct value assignment alone to create new items given existing key):
student["grade"] = "A" # assign a value to specified key
print (student) #{'name': 'Alice', 'age': 20, 'grade': 'A'}
#Change a key (re-assignment to a new value using existing or recently assigned keys without needing to make temporary objects during operations unlike where keys would be immutable or typecast explicitly before next value change like a list rather than set being assigned)
student["age"] = 22
print (student) #{'name': 'Alice', 'age': 22, 'grade': 'A'}

4. Removing Dictionary Items:

mydict = {'Physics': 82, 'Math': 65, 'history': 75}
print(mydict.pop('history')) # this method will remove 'history' and return its value 75 which could go into some `ret` val rather than discard if needing this later elsewhere as example assumes without other context given current limited scope del mydict['Physics']
print (mydict) # prints {'Math': 65} since value discarded this way which is usual and default intended outcome with removal unless specified since value retained in print or when calling `del()` with positional index on ordered construct which differs due to ordered properties from non-ordered case here using dicts and associated functionality related to mutable content rather than sequence metadata even if a key also treated as an identifier unlike int positional indices for mutable-length dynamic variables like List
mydict.clear() # delete all items within and thereby creating an empty Dict assuming no subsequent use as it's cleared to make effectively same empty/initial instance as earlier at point right before further modifications have taken effect

5. Common Dictionary Methods

Main/frequently applicable examples of dictionary methods, presented similarly using `

` formatting as other sections. Note use cases discussed briefly with most, indicating their function, thereby suggesting situations they prove particularly useful:

Method Description Example
keys() returns all keys or associated index style accessors within the dictionary. When creating dictionary indexing methods one common step generates dict keys which could provide valid field/col style descriptors, assuming data consistent, since no repetition given Dict as seen with list/sets where similar or same key element-value type could become inconsistent with dict style lookups assuming keys also considered immutable as standard dict implementation does where index approach may differ due to ordering expectations on such constructs which dicts not limited by (unordered)
my_dict = {"a": 10, "b": 20, "c":30} all_keys = my_dict.keys()
print(all_keys) #dict_keys(['a', 'b', 'c']). Note also since it prints out all keys from that object itself you don't need a function or method operating within dictionary, like a similar type `values()` which also provided below and performs effectively similarly given dictionary construct assumptions regarding structure as expected
values() Return all val within the dictionary, using each to iterate directly over type even without access to keys as done using preceding function method which would give some ordered element-wise way through similar to other sequences by contrast
dict1 = {"a": 1, "b": 2, "c": 3} dict_values= dict1.values() print (dict_values) # dict_values([1, 2, 3]). As noted like prior keys method usage they also become values at same point given data stored to initialize a dict rather than by special functionality for lists alone. It remains valid approach where also like any set of sequences that data stored in-place without further requirements unless otherwise required since even as separate they can still function much same unlike if key were ordered within construct, even though not ordered here
items() returns pairs, if used at a prior stage before extracting either items or value independently. Unlike Lists no positional data to loop over where each valid item already has a mapping between associated pairs such that there would always only one entry if found (given dict key must have exactly one valid value from assignment to that data in contrast to other unordered, unique instances when some count not a multiple assuming any valid indices as would normally arise given unordered construct) since otherwise that would end up breaking ordering during iterations by looping unless checked during steps
mydict= {"a":1, "b":2, "c":3} items=mydict.items()
print(items) #dict_items([('a', 1), ('b', 2), ('c', 3)])
copy() Returns dictionary's copy. Note for dicts copy operation shallow means any nested elements or lists inside the data will modify when originals do, assuming appropriate references/values during initial object type declaration at object instantiation such as `id` value for nested type like another `Dict` or related `Set` within current Dict given scope which would follow reference not value at time after being copied unlike simple string elements or integers in code example
original_dict = {"a": 1, "b": 2, "c": 3}
copied_dict = original_dict.copy() # Creates shallow copy rather than full deep or recursively cloned instance when performing `copy` steps
# modifying original should not effect copied one unless special reference behaviour involved, especially when using such within contexts with complex `oop` implementations original_dict["a"] = 10 # modify item only of our `original_dict` and leave others untouched in both. Try changing 'a' for b, or if values the same during test by updating that `int` directly, e.g. 'a'=2 assuming any tests done are using distinct values with unique `hash()` outputs given type (where applicable), assuming appropriate overrides applied rather than assuming original will work or raise appropriate type errors/messages given data involved in subsequent method chains where applicable print("Original Dictionary:",original_dict ) # {'a': 10, 'b': 2, 'c': 3}
print("Copied Dictionary:", copied_dict) # Output: {'a': 1, 'b': 2, 'c': 3}
popitem() Python 3.7+: removes/returns last key-value pairs at any one stage as determined within interpreter context alone without needing ordered elements otherwise from ordered key type within that dict which thereby could have different index mappings given non-ordered dictionary which remains guaranteed unique even without sorting unlike similar operations when using an array where items could clash unless a positional value enforced such as via use of a stack implemented over an ordered collection (unlike dictionary types with shallow copying, implicit sorting where needed assuming ordered key or if sorting keys first for later sorting if required unlike lists retaining sequence data for that purpose), etc. where IndexError possible exception raised only for already empty dictionaries unless same value key introduced via new items added such as a similar `key: value` where implicit hash or value equality test then indicates clash since only ever assigned at once like for dict which differs if adding into List for this reason too
person = {'name': 'Alice', 'age': 32, 'City': 'NY'} result= person.popitem() # it pops up 'City':'NY', not dependent on alphabetic order
print (person) #{'name': 'Alice', 'age': 32}
print (result) # ('City','NY') # like List operations `pop()` will return the element-value pairs extracted in effect from such implicit "stack" removal from current Dictionary
dict1 = {} #popped_item = dict1.popitem() # it raises KeyError on the already empty/newly instantiated dicts given scope assuming key/values not yet present in this local `dict1` as shown so would crash or exit since otherwise no data present yet even before any other subsequent usage like tests on nested list which in preceding case could pass test to make such calls to `.popitem()` in that situation after creating that dictionary
get() Returns value from that key if such exists, with KeyError if such a key isn't in dictionary where some similar cases use alternate default method or specify how KeyError type handled
sales = {'apple': 2, 'orange': 3, 'grapes': 4} print(sales.get("apple")) #2. Returns corresponding to given key's current/active latest element-value
print(sales.get("guava",0)) # since sales doesn’t have `guava`, you're returning its explicitly given argument from `get() `function: 0 print(sales.get("banana")) # Since Key "Banana" doesn’t exist you obtain default output rather than error :None rather than 'default' as explicit value when prior step checked if dict contents missing by passing zero rather than letting it be the usual special value returned on such error by simply specifying value in arguments when function/method invoked directly here (by `sales.get("guava", 0)` calling in that preceding scope