# Python language Tutorial
## Comments
```python=
# comment 1
"""
comment 2
"""
```
## Variables
### Assign multiple values
- Many values to multiple variables
```python=
x, y, z = "frist", "second", "third"
```
- One Value to multiple variables
```python=
x = y = z = "frist"
```
- Unpack a collection
```python=
fruits = ["apple", "banana", "cherry"]
x, y, z = fruits
```
### Output variables
- expression 1
```python=
x = "This is an example."
print(x)
```
- expression 2
```python=
a, b, c, d, e = "This", "is", "an", "example" ,"."
print(a, b, c, d, e)
```
- expression 3
```python=
a, b, c, d, e = "This ", "is ", "an ", "example" ,"."
print(a + b + c + d + e)
```
In the `print()` function, when you try to combine a string and a number, there will be error with the + operator. The best way to output multiple variables in the `print()` function is to separate them with commas.
```python=
x, y = "Chapter", 1
print(x, y)
```
### Global variables
Variables that are created outside of a function are known as global variables. Global variables can be used by everyone, both inside of functions and outside.
```python=
x = "global"
def myfunc():
print("This variable is " + x)
myfunc()
```
If you create a variable with the same name inside a function, this variable will be local, and can only be used inside the function. The global variable with the same name will remain as it was, global and with the original value.
```python=
x = "global"
def myfunc():
x = "locl"
print("This variable is " + x)
myfunc()
print("This variable is " + x)
```
Normally, when you create a variable inside a function, that variable is local, and can only be used inside that function. To create a global variable inside a function, you can use the <font color="#0000ff">`global`</font> keyword.
The variable belongs to the global scope when it is used with the global keyword,
```python=
def myfunc():
global x
x = "global"
myfunc()
print("This variable is " + x)
```
Using the global keyword can change a global variable inside a function.
```python=
x = "global"
def myfunc():
global x
x = "inside"
myfunc()
print("This variable is " + x)
```
## Data types
### Built-in data types
| Categories | Data type |
| -------------- |:---------------------------- |
| Text Type | str |
| Numeric Types | int, float, complex |
| Sequence Types | list, tuple, range |
| Mapping Type | dict |
| Set Types | set, frozenset |
| Boolean Type | bool |
| Binary Types | bytes, bytearray, memoryview |
| None Type | NoneType |
| Assign | Casting(Specify) | Data type |
| ------------------------------- |:-------------------------------- | :--------- |
| x = "str" | x = str("str") | str |
| x = 26 | x = int(26) | int |
| x = 26.1 | x = float(26.1) | float |
| x = 1j | x = complex(1j) | complex |
| x = [1, 2, 3] | x = list((1, 2, 3)) | list |
| x = (1, 2, 3) | x = tuple((1, 2, 3)) | tuple |
| x = range(6) | x = range(6) | range |
| x = {"key": "one", "value" = 1} | x = dict(key = "one", value = 1) | dict |
| x = {1, 2, 3} | x = set((1, 2, 3)) | set |
| x = frozenset({1, 2, 3}) | x = frozenset((1, 2, 3)) | frozenset |
| x = True | x = bool(5) | bool |
| x = b"Hello" | x = bytes(5) | bytes |
| x = bytearray(5) | x = bytearray(5) | bytearray |
| x = memoryview(bytes(5)) | x = memoryview(bytes(5)) | memoryview |
| x = None | | NoneType |
### Integer - int
| Prefix | Exptreesion | System |
| ------ |:----------- |:---------- |
| 0b, 0B | a = 0b1010 |Binary |
| 0o, 0O | a = 0o12 |Octal |
| | a = 10 |Decimal |
| 0x, 0X | a = 0xa |Hexadecimal |
### Floating point number - float
- expression 1: a = 0.04
- expression 2: a = .04
- expression 3: a = 4e-2 (4E-2)
The `type()` function either returns the type of the object or returns a new type object based on the arguments passed.
### String - str
```python=
a = """Line 1
Line 2
Line 3"""
b = '''Line 1
Line 2
Line 3'''
print(a)
print(b)
```
#### format string
```python=
name = "Kitty"
age = 50
method_1 = "My name is " + name + ". I'm " + str(age) + " years old."
print(method_1)
method_2 = "My name is %s. I'm %d years old." % (name, age)
print(method_2)
method_3 = "My name is {}. I'm {} years old.".format(name, age)
print(method_3)
method_4 = "My name is {name}. I'm {age} years old.".format(name="Kitty", age=50)
print(method_4)
method_5 = f"My name is {name}. I'm {age} years old."
print(method_5)
```
### None
```python=
print(None == '')
```
### Escape characters
| Character | Result |
| ---------- |:------------ |
| \\\' | Single Quote |
| \\\\ | Backslash |
| \n | New Line |
| \t | Tab |
### List methods
- `count()`
```python=
list_1 = [4, 5, 6, 4, 5, 4]
print(list_1.count(4))
```
- `append()`
```python=
list_1 = [1, 2, 3]
list_1.append(4)
print(list_1)
```
- `insert()`
```python=
list_1 = [1, 2, 3]
list_1.insert(1, 4)
print(list_1)
```
- `extend()`
```python=
list_1 = [1, 2, 3]
list_2 = [4, 5, 6]
list_1.extend(list_2)
tuple_1 = (7, 8)
list_1.extend(tuple_1)
print(list_1)
```
- `remove()`
```python=
list_1 = [4, 5, 6]
list_1.remove(2)
print(list_1)
```
- `pop()`
```python=
list_1 = [4, 5, 6]
list_1.pop(1)
print(list_1)
```
- `del`
```python=
list_1 = [4, 5, 6]
del list_1[1]
print(list_1)
del list_1
print(list_1)
```
- `clear()`
```python=
list_1 = [4, 5, 6]
list_1.clear()
print(list_1)
```
- `sort()`
```python=
list_1 = [6, 4, 5, 1, 9, 2, 3]
list_1.sort()
print(list_1)
list_2 = [6, 4, 5, 1, 9, 2, 3]
list_2.sort(reverse = True)
print(list_2)
```
- `reverse()`
```python=
list_1 = [6, 4, 5, 1, 9, 2, 3]
list_1.reverse()
print(list_1)
```
- `copy()`
```python=
list_1 = [6, 4, 2, 3]
list_2 = list_1.copy()
print(list_2)
```
- `list()`
```python=
list_1 = [6, 4, 2, 3]
list_2 = list(list_1)
print(list_2)
```
### Tuple
A tuple with only one item have to add a comma after the item, otherwise Python will not recognize it as a tuple.
```python=
tuple_1 = (1,)
print(type(tuple_1))
tuple_2 = (1)
print(type(tuple_2))
tuple_3 = 1,
print(type(tuple_3))
tuple_4 = 1
print(type(tuple_4))
```
Tuples are unchangeable (immutable), once a tuple is created, it cannot be changed its values. But, tuples can convert the tuple into a list, change, add, remove item in the list, and convert the list back into a tuple.
```python=
# change tuple values
tuple_1 = (2, 3, 4)
tuple_2 = list(tuple_1)
tuple_2[1] = 5
tuple_1 = tuple(tuple_2)
print(tuple_1)
# add items
tuple_3 = (2, 3, 4)
tuple_4 = list(tuple_3)
tuple_4.append(5)
tuple_3 = tuple(tuple_4)
print(tuple_3)
# add items
tuple_5 = (2, 3, 4)
tuple_6 = (5,)
tuple_5 += tuple_6
print(tuple_5)
# remove
tuple_7 = (2, 3, 4)
tuple_8 = list(tuple_7)
tuple_8.remove(3)
tuple_7 = tuple(tuple_8)
print(tuple_7)
tuple_9 = (1, 2, 3)
del tuple_9
print(tuple_9) # this will raise an error because the tuple no longer exists
```
There are two types of objects in Python: 'mutable' and 'immutable'. Lists come under mutable objects and tuples comes under immutable objects.
Tuples are stored in a single block of memory. Tuples are immutable so, It doesn't require extra space to store new objects. Lists are allocated in two blocks: the fixed one with all the Python object information and a variable-sized block for the data. It is the reason creating a tuple is faster than List.
#### Unpack tuples
[Python - Unpack Tuples | w3schools ](https://www.w3schools.com/python/python_tuples_unpack.asp)
### Set
- `set()`
```python=
list_1 = [1, 2, 3, 3, 2, 3, 4, 3]
set_1 = set(list_1)
print(set_1)
set_1.add(5)
print(set_1)
set_1.add(5)
set_1.add(5)
print(set_1)
```
- `add()`
```python=
set_1 = {1, 2, 3}
set_1.add(4)
print(set_1)
```
- `update()`
```python=
set_1 = {1, 2, 3}
set_2 = {4, 5, 6}
set_3 = [7, 8, 9]
set_1.update(set_2)
set_1.update(set_3)
print(set_1)
```
- `remove()`
If the item to remove does not exist, remove() will raise an error.
```python=
set_1 = {1, 2, 3}
set_1.remove(2)
print(set_1)
```
- `discard()`
If the item to remove does not exist, discard() will NOT raise an error.
```python=
set_1 = {1, 2, 3}
set_1.discard(2)
print(set_1)
```
- `pop()`
```python=
set_1 = {1, 2, 3}
x = set_1.pop()
print(x)
print(set_1)
```
- `clear()`
```python=
set_1 = {1, 2, 3}
set_1.clear()
print(set_1)
```
- `del`
```python=
set_1 = {1, 2, 3}
del set_1
print(set_1)
```
- `union()`
```python=
set_1 = {1, 2, 3}
set_2 = {4, 5, 6}
set_3 = set_1.union(set_2)
print(set_3)
```
- `intersection_update()`
```python=
set_1 = {1, 2, 3}
set_2 = {4, 5, 3}
set_1.intersection_update(set_2)
print(set_1)
```
- `symmetric_difference()`
```python=
set_1 = {1, 2, 3}
set_2 = {4, 5, 3}
set_3 = set_1.symmetric_difference(set_2)
print(set_3)
```
- `&`, `|`, `^`, `-`
```python=
set_1 = {1, 2, 3, 4}
set_2 = {3, 4, 5, 6}
print(set_1 & set_2)
print(set_1 | set_2)
print(set_1 ^ set_2)
print(set_1 - set_2)
print(set_2 - set_1)
```
### Dictionaries - dict
- `keys()`
```python=
a = dict(brand = "Ford", model = "Mustang")
print(a)
print(type(a))
```
- `get()`
```python=
car = {
"brand": "Ford",
"model": "Mustang",
}
print(car.get("year"))
print(car["year"])
```
- `keys()` , `values()`, `items()`
```python=
car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
x = car.keys()
print(x) #before the change
car["color"] = "white"
print(x) #after the change
y = car.values()
print(y) #before the change
car["year"] = 2020
print(y) #after the change
car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
z = car.items()
print(z) #before the change
car["year"] = 2020
print(z) #after the change
```
- `update()`, `pop()`
```python=
car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
car.update({"year": 2020})
car.update({"color": "red"})
print(car)
car.pop("model")
print(car)
```
- `clear()`, `del`
```python=
car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
car.clear()
print(car)
del car
print(car)
```
##### Copy a dictionary
We cannot copy a dictionary simply by typing dict2 = dict1, because: dict2 will only be a reference to dict1, and changes made in dict1 will automatically also be made in dict2.
There are ways to make a copy, one way is to use the built-in Dictionary method `copy()`.
Another way to make a copy is to use the built-in function `dict()`.
```python=
dict_1 = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
dict_2 = dict_1.copy()
print(dict_2)
dict_3 = dict(dict_1)
print(dict_3)
```
There are four collection data types in the Python programming language.
- List is a collection which is ordered and changeable. Allows duplicate members.
- Tuple is a collection which is ordered and unchangeable. Allows duplicate members.
- Set is a collection which is unordered, unchangeable, and unindexed. No duplicate members.
- Dictionary is a collection which is ordered and changeable. No duplicate members.
| Data type | un/ordered | un/changable | duplicate value |
| ---------- | :--------- | :----------- | :-------------- |
| list | ordered | changable | allow |
| tuple | ordered | unchangable | allow |
| set | unordered | unchangable | no |
| dictionary | ordered | changable | no |
## Operators
### Arithmetic operators
| Operator | Name |
| -------- |:-------------- |
| / | Division |
| % | Modulus |
| ** | Exponentiation |
| // | Floor division |
### Bitwise Operators
| Operator | Name | Description |
| -------- |:-------------- |:---|
| & | AND | Sets each bit to 1 if both bits are 1. |
| \| | OR | Sets each bit to 1 if one of two bits is 1. |
| ^ | XOR | Sets each bit to 1 if only one of two bits is 1. |
| ~ | NOT | Inverts all the bits. |
| << | Zero fill left shift | Shift left by pushing zeros in from the right and let the leftmost bits fall off. |
| >> | Signed right shift | Shift right by pushing copies of the leftmost bit in from the left, and let the rightmost bits fall off. |
## Conditions
method 1:
```python=
a = 3
b = 2
if b > a: print("b is greater than a")
elif a == b: print("a and b are equal")
else: print("a is greater than b")
```
method 2:
```python=
a = 2
b = 330
print("A") if a > b else print("B")
```
method 3:
```python=
a = 1
b = 2
if b > a: pass
```
## Loop
- `while`
```python=
i = 0
while i < 8:
i += 1
if i == 3:
continue
if i == 6:
break
print(i)
```
```python=
i = 1
while i < 6:
print(i)
i += 1
else: print("i is no longer less than 6")
```
- `for`
```python=
nums = [1, 2, 3, 4, 5]
for i in nums:
print(i)
for i in range(len(nums)):
print(nums[i])
```
```python=
for i in range(2, 6):
print(i)
for i in range(2, 8, 3):
print(i)
```
```python=
for i in range(4): print(x)
else: print("Done")
```
```python=
for i in [0, 1, 2]: pass
```
## Functions
```python=
def my_function(fname, lname):
print(fname + " " + lname)
my_function("Emil", "Refsnes")
def my_function_2(num_1, num_2):
print(num_1, num_2, num_1 + num_2)
my_function_2(num_2 = 5, num_1 = 2)
```
```python=
a = [1, 2, 3]
b = [1, 2, 3]
c = 2
def f_1(x):
x.append(4)
f_1(a)
print(a)
def f_2(x):
x = x + [4]
f_2(b)
print(b)
def f_3(x):
global c
c = c + x
f_3(5)
print(c)
```
### Arbitrary arguments, *args
If we do not know how many arguments that will be passed into your function, add a * before the parameter name in the function definition.
This way the function will receive a tuple of arguments, and can access the items accordingly.
```python=
def my_function(*kids):
print("The youngest child is " + kids[2])
my_function("Emil", "Tobias", "Linus")
```
### Keyword arguments
We can also send arguments with the key = value syntax.
This way the order of the arguments does not matter.
```python=
def my_function(child3, child2, child1):
print("The youngest child is " + child3)
my_function(child3 = "Linus", child1 = "Emil", child2 = "Tobias")
```
### Arbitrary keyword arguments, **kwargs
```python=
def my_function(**kid):
print("His last name is " + kid["lname"])
my_function(fname = "Tobias", lname = "Refsnes")
```
```python=
def f_1(**kwargs):
return (kwargs.get('a') + kwargs.get('b') + kwargs.get('c'))
print(f_1(b = 2, c = 5, a = 6))
```
```python=
def f_2(a, b):
print(a + b)
def f_3(x, **kwargs):
if x == 2:
f_2(**kwargs)
f_3(b = 2, x = 2, a = 1)
```
### Default parameter value
```python=
def my_function(country = "Norway"):
print("I am from " + country)
my_function("Sweden")
my_function()
```
### The pass statement
```python=
def myfunction(): pass
```
##
```python=
class daynames:
def __init__(self, dataval=None):
self.dataval = dataval
self.nextval = None
e1 = daynames('Mon')
e2 = daynames('Wed')
e3 = daynames('Tue')
e4 = daynames('Thu')
e1.nextval = e3
e3.nextval = e2
e2.nextval = e4
thisvalue = e1
while thisvalue:
print(thisvalue.dataval)
thisvalue = thisvalue.nextval
```
## Lambda
A lambda function is a small anonymous function.
A lambda function can take any number of arguments, but can only have one expression.
```python=
def myfunc(n): return lambda a : a * n
mydoubler = myfunc(2)
mytripler = myfunc(3)
print(mydoubler(11))
print(mytripler(11))
```
## Underscore (_)
Following are different places where “_” is used in Python:
- Single Underscore:
- Single Underscore in Interpreter
- Single Underscore after a name
- Single Underscore before a name
- Single underscore in numeric literals
- Double Underscore:
- Double underscore before a name
- Double underscore before and after a name
### Single Underscore example 1: Single Underscore In Interpreter
_ returns the value of the last executed expression value in Python Prompt/Interpreter.
```cmd=python
>>> a = 10
>>> b = 10
>>> _
>>> a + b
>>> _
>>> _ * 2
>>> _
>>> _ / 2
>>> _
```
### Single Underscore example 2: Single Underscore for ignoring values
Multiple times we do not want return values at that time to assign those values to Underscore. It is used as a throw-away variable.
???
### Single Underscore example 3: Single Underscore after a name
Python has theirs by default keywords which we can not use as the variable name. To avoid such conflict between python keyword and variable we use underscore after the name
```python=
def my_function(num = 5, if_ = 3):
print(num)
print(if_)
my_function()
```
[Python Keywords](https://www.geeksforgeeks.org/python-keywords/)
### Single Underscore example 4: Single Underscore before a name
Leading Underscore before variable/function /method name indicates to the programmer that It is for internal use only, that can be modified whenever the class wants. Here name prefix by an underscore is treated as non-public. If specify `from Import *` all the names starting with _ will not import. Python does not specify truly private so this one can be called directly from other modules if it is specified in \_\_all__, We also call it weak Private.
```python=
# module_1.py
def public_func():
print("I'm available.")
def _private_func():
print("I'm not available")
```
```python=
# project_1.py
from module_1 import *
public_func()
_private_func()
```
```python=
# project_2.py
from module_1 import _private_func
_private_func()
```
```python=
# module_2.py
__all__ = ['public_func', '_private_func']
def public_func():
print("I'm available.")
def _private_func():
print("I'm not available")
```
```python=
# project_3.py
from module_2 import *
public_func()
_private_func()
```
### Single Underscore example 5: Single underscore in numeric literals
The Python syntax is utilized such that underscores can be used as visual separators for digit grouping reasons to boost readability. This is a typical feature of most current languages and can aid in the readability of long literals, or literals whose value should clearly separated into portions.
```python=
# grouping decimal for easy readability of long literals
amount = 10_000_000.0
# grouping hexadecimal for easy readability of long literals
addr = 0xCAFE_F00D
# grouping bits for easy readability of long literals
flags = 0b_0011_1111_0100_1110
print(amount)
print(addr)
print(flags)
```
### Double Underscore example 1: Double underscore before a name
The leading double underscore tells the Python interpreter to rewrite the name in order to avoid conflict in a subclass. Interpreter changes variable name with class extension and that feature known as the Mangling.
```python=
class Jason:
location = 'HsinChu'
favorite_movie = 'Inception'
hobby = 'card magic'
__wife = 'Mary'
def profile(self):
"""Print my personal profile."""
print(f'''
I live in {self.location}
My favorite movie is {self.favorite_movie}
My hobby is {self.hobby}
My wife is {self.__wife}
''')
Jason().profile()
class Aji(Jason):
location = 'Taipei'
__wife = 'Boa'
Aji().profile()
jason = Jason()
print(jason.location)
try:
print(jason.__wife)
except:
print("==error==")
print(jason._Jason__wife)
```
### Double Underscore example 2: Double underscore before and after a name
The name starts with __ and ends with the same considering special methods in Python. Python provides these methods to use as the operator overloading depending on the user. Python provides this convention to differentiate between the user-defined function with the module’s function .
ref:
[GOG](https://www.geeksforgeeks.org/underscore-_-python/)
[https://aji.tw/2017/06/python%E4%BD%A0%E5%88%B0%E5%BA%95%E6%98%AF%E5%9C%A8__%E5%BA%95%E7%B7%9A__%E4%BB%80%E9%BA%BC%E5%95%A6/](https://aji.tw/2017/06/python%E4%BD%A0%E5%88%B0%E5%BA%95%E6%98%AF%E5%9C%A8__%E5%BA%95%E7%B7%9A__%E4%BB%80%E9%BA%BC%E5%95%A6/)
## Generator
### Iterable
Strings, Lists, tuples, dictionaries, and sets are all iterable objects. They are iterable containers which you can get an iterator from.
```python=
def test():
yield 3
print("===")
yield 5
gen = test()
for i in gen:
print(i)
```
```python=
def yield_test(n):
print("start n = ", n)
for i in range(n):
yield i * i
print("i = ", i)
print("end")
tests = yield_test(5)
for test in tests:
print("test = ", test)
print("--------")
```
ref:
[https://www.youtube.com/watch?v=x6MNOSRY5EM](https://www.youtube.com/watch?v=x6MNOSRY5EM)
[https://iter01.com/595236.html](https://iter01.com/595236.html)
[https://ithelp.ithome.com.tw/articles/10258195](https://ithelp.ithome.com.tw/articles/10258195)
## Classes and Objects
Python is an object oriented programming language.
Almost everything in Python is an object, with its properties and methods.
A Class is like an object constructor, or a "blueprint" for creating objects.
### The __init__() function
All classes have a function called __init__(), which is always executed when the class is being initiated.
Use the __init__() function to assign values to object properties, or other operations that are necessary to do when the object is being created.
The __init__() function is called automatically every time the class is being used to create a new object.
```python=
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p1 = Person("John", 36)
print(p1.name)
print(p1.age)
```
### Object methods
```python=
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def myfunc(self):
print("Hello my name is " + self.name)
p1 = Person("John", 36)
p1.myfunc()
```
### Inheritance
Inheritance allows us to define a class that inherits all the methods and properties from another class.
```python=
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname
def printname(self):
print(self.firstname, self.lastname)
class Student_1(Person):
def __init__(self, fname, lname):
Person.__init__(self, fname, lname)
class Student_2(Person):
def __init__(self, fname, lname):
super().__init__(fname, lname)
s1 = Student_1("f_1", "l_1")
s2 = Student_2("f_2", "l_2")
s1.printname()
s2.printname()
```
## Modules
To create a module just save the code you want in a file with the file extension `.py`.
> Save this code in a file named mymodule.py
```python=
def greeting(name):
print("Hello, " + name)
person1 = {
"name": "John",
"age": 36,
"country": "Norway"
}
```
```python=
import mymodule
mymodule.greeting("Jonathan")
a = mymodule.person1["age"]
print(a)
```
```python=
import mymodule as mx
a = mx.person1["age"]
print(a)
```
- `dir()`
```python=
import platform
x = dir(platform)
print(x)
```
### __all__
It's a list of public objects of that module, as interpreted by `import *`. It overrides the default of hiding everything that begins with an underscore.
## Try except
The `try` block lets you test a block of code for errors.
The `except` block lets you handle the error.
The `else` block lets you execute code when there is no error.
The `finally` block lets you execute code, regardless of the result of the try- and except blocks.
```python=
try:
print("Hello")
except:
print("Something went wrong")
else:
print("Nothing went wrong")
try:
print(x)
except:
print("Something went wrong")
finally:
print("The 'try except' is finished")
```
### Raise an exception
```python=
x = -1
if x < 0:
raise Exception("Sorry, no numbers below zero")
```
## Methods
### String methods
| Method | Description |
| -------- |:---------------------------------------------------------------------- |
| format() | Formats specified values in a string. |
| zfill() | Fills the string with a specified number of 0 values at the beginning. |
ref:
[w3schools](https://www.w3schools.com/python/python_ref_string.asp)
## Collections Module
The collection Module in Python provides different types of containers. A Container is an object that is used to store different objects and provide a way to access the contained objects and iterate over them. Some of the built-in containers are Tuple, List, Dictionary, etc. In this article, we will discuss the different containers provided by the collections module.
Table of Content: Counters, OrderedDict, DefaultDict, ChainMap, NamedTuple, DeQue, UserDict, UserList, UserString
### DefaultDict
A DefaultDict is also a sub-class to dictionary. It is used to provide some default values for the key that does not exist and never raises a KeyError.
```python=
from collections import defaultdict
# 1
better_dict = defaultdict(list)
print(better_dict['a'])
better_dict['b'].append(1)
better_dict['b'].append(2)
better_dict['b'].append(3)
print(better_dict['b'])
print(better_dict['a'])
# 2
multi_dict = defaultdict(list)
key_values = [('even', 2), ('odd', 1), ('even', 8), ('odd', 3), ('float', 2.4), ('odd', 7)]
for key, value in key_values:
multi_dict[key].append(value)
print(multi_dict)
# 3
def zero(): return 0
counter_dict = defaultdict(zero)
a_list = ['a', 'b', 'x', 'a', 'a', 'b', 'z']
for element in a_list:
counter_dict[element] += 1
print(counter_dict)
```
ref:
[GFG](https://www.geeksforgeeks.org/python-collections-module/)
[IT](https://ithelp.ithome.com.tw/articles/10193094)
## Random Module
```python=
import random
print(random.randint(3, 9))
```
```python=
```
ref:
[w3schools](https://www.w3schools.com/python/default.asp)
[Programiz](https://www.programiz.com/)