-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathchapter2.py
293 lines (224 loc) · 9.14 KB
/
chapter2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
####################################################
# 2. Variables and Collections
####################################################
# Python has a function to print
print("I'm Python. Nice to meet you.")
# There is no need to declare variables before assigning them.
a_variable = 5 # The convention is to use lowercase underscores (snake_case).
one_variable: float = 5 # Optional type-hints | RECOMMENDED
one_variable # => 5
# other_variable # Error unassigned variable
# Operators with re-assignment
one_variable += 2 # one_variable == 7
one_variable -= 1 # one_variable == 6
one_variable *= 5 # one_variable == 30
one_variable /= 5 # one_variable == 3.0
one_variable **= 3 # one_variable == 27.0
one_variable %= 10 # one_variable == 7.0
one_variable //= 5 # one_variable == 1.0
# Multiple assignment
a = b = 3 # a = 3 and b = 3
####################################################
# 2.1 Lists
####################################################
# Lists stores sequences
some_list = [] # Empty
other = [4, 5, 6] # With initial values
multiple = [2, "John", [2]] # Values of different type (heterogeneous)
# List methods
some_list.append(1) # Add an element at the end
some_list.extend([2, 4, 3]) # Add multiple elements
some_list.pop() # => 3 and list=[1, 2, 4])
some_list.insert(3, 3) # Add an element at the given position
len(some_list) # 4
# Simple indexing
some_list[0] # => 1 First element
some_list[-1] # => 4 Last element
# some_list[4] # Error - Out of bounds
# Slicing list[start:end:step]
some_list[1:3] # => [2, 4]
some_list[2:] # => [4, 3]
some_list[:3] # => [1, 2, 4]
some_list[::2] # => [1, 4]
some_list[::-1] # => [3, 4, 2, 1]
some_list[:] # => Creates an identical copy of list
# Operations with Lists
some_list + other # => [1, 2, 4, 3, 4, 5, 6]
some_list * 2 # => [1, 2, 4, 3, 1, 2, 4, 3]
# Operator in
1 in some_list # => True
# The not operator can be used before or after
not 5 in some_list # => True
5 not in some_list # => True
# Operator ==
some_list == [1, 2, 4, 3] # => True
some_list == some_list[:] # => True
some_list == some_list # => True
# Operator is
some_list is [1, 2, 4, 3] # => False
some_list is some_list[:] # => False
some_list is some_list # => True
# Special operations for Boolean lists
any(some_list) # => True | Returns True if at least one of the elements is True
all(some_list) # => True | Returns True if all the elements are True
####################################################
# 2.2 Tuples, immutable collections
####################################################
empty_tuple = tuple() # Constructed with the tuple function
some_tuple = (1, 2, 3) # They are defined with (,) instead of []
some_tuple = 1, 2, 3 # Parentheses are optional
some_tuple[0] # => 1
# some_tuple[0] = 3 # TypeError
one_element_tuple = (3,) # Comma is mandatory
one_element_tuple = 3, # Parentheses are optional
# Methods identical to lists but without assignment
len(some_tuple) # => 3
some_tuple + (4, 5, 6) # => (1, 2, 3, 4, 5, 6)
some_tuple[:2] # => (1, 2)
2 in some_tuple # => True
####################################################
# 2.3 Unpacking
####################################################
# Simple unpacking
a, b, c = (1, 2, 3) # a == 1, b == 2, c == 3
a, b, c = [1, 2, 3] # a == 1, b == 2, c == 3
# a, b = [1, 2, 3] # Error | Number of elements must be identical
a, b = b, a # Exchange a == 2, b == 1
# Unpacking With wildcards
a, *rest = [1, 2, 3, 4] # a == 1, rest == [2, 3, 4]
*rest, b = [1, 2, 3, 4] # b == 4, rest == [2, 3, 4]
a, *rest, b = [1, 2, 3, 4] # a == 1, b == 4, rest == [2, 3]
# Nested Unpacking
(a, b), c = [[1, 2], [3]] # a == 1, b == 2, c == [3]
####################################################
# 2.4 Dictionaries - Key-Value Collections
####################################################
empty_dictionary = {} # Empty
dictionary = {
"one": 1, # Multiline declaration
"two": 2,
"three": 3, # Comma at the end valid
}
dictionary["one"] # => 1 - Indexed with Keys
# dictionary["four"] # Error
dictionary.get("one") # => 1
dictionary.get("four") # => None instead of Error
dictionary.get("one", 4) # => 1
dictionary.get("four", 4) # => Default value instead of None
# Methods
list(dictionary.keys()) # => ["three", "two", "one"] # => ["three", "two", "one"]
list(dictionary.values()) # => [3, 2, 1] # => ["three", "two", "one"] # => [3, 2, 1
list(dictionary.items()) # => [('one', 1), ('two', 2), ('three', 3)]
# Operators with Dictionaries | in verifies the keys.
"one" in dictionary # => True
1 in dictionary # => False
# Dictionary update
new_data = {"four": None, "five": 5}
dictionary.update(new_data)
dictionary # {'one': 1, 'two': 2, 'three': 3, 'four': None, 'five': 5}
# Keys and values could be Heterogeneous
multiple = {
"one": 1,
2: "two",
(1, 3): [1, 5],
}
# Keys must be inmutable (hashable)
# invalid = {[1, 2]: "1"} # Error
####################################################
# 2.4 Sets | Collections without duplicates
####################################################
empty_set = set()
some_set = {1, 2, 2, 2, 3, 4} # => {1, 2, 3, 4}
some_set.add(5) # => {1, 2, 3, 4, 5}
some_set.add(6) # => {1, 2, 3, 4, 5, 6}
some_set.discard(7) # => {1, 2, 3, 4, 5, 6}
# some_set.remove(7) # => Error | Remove assumes element is in set
some_set.remove(6) # => {1, 2, 3, 4, 5, 6}
# Set Operations
other_set = {3, 4, 5, 6}
# In Operator
2 in some_set # => True
# Intersection
some_set & other_set # => {3, 4, 5}
some_set.intersection(other_set) # => {3, 4, 5}
# Union
some_set | other_set # => {1, 2, 3, 4, 5, 6}
some_set.union(other_set) # => {1, 2, 3, 4, 5, 6}
# Difference
some_set - other_set # => {1, 2}
some_set.difference(other_set) # => {1, 2}
# Symmetric difference
some_set ^ other_set # => {1, 2, 5, 6}
some_set.symmetric_difference(other_set) # => {1, 2, 5, 6}
# Subset
subset = {1, 2, 3, 4, 5}
subset <= some_set # => True
subset.issubset(some_set) # => True
# Proper Subset
proper_subset = {1, 2, 3}
subset < some_set # => False
proper_subset < some_set # => True
# Superset
superset = {1, 2, 3, 4, 5}
superset >= some_set # => True
superset.issuperset(some_set) # => True
# Proper Superset
proper_superset = {1, 2, 3, 4, 5, 6}
superset > some_set # => False
proper_superset > some_set # => True
# Disjoint
extra_set = {9, 10, 11}
some_set.intersection(other_set) == set() # => False
some_set.isdisjoint(other_set) # => False
some_set.intersection(extra_set) == set() # => True
some_set.isdisjoint(extra_set) # => True
####################################################
# 2.5 Frozensets | Sets but immutable
####################################################
empty_frozenset = frozenset()
some_frozenset = frozenset({1, 2, 3}) # Can be created from a set
some_frozenset = frozenset([1, 2, 3]) # Or any other iterable
# some_frozenset.add(3) # AttributeError
# Methods identical to sets but without assignment
some_frozenset = frozenset({1, 2, 3, 4, 5, 6})
other_set = {3, 4, 5, 6}
other_frozenset = frozenset({3, 4, 5, 6})
len(some_frozenset) # => 6
some_frozenset | other_set # => frozenset({1, 2, 3, 4, 5, 6})
some_frozenset | other_frozenset # => frozenset({1, 2, 3, 4, 5, 6})
2 in some_frozenset # => True
####################################################
# 2.6 Recursive Collections
####################################################
"""
Although it is not common, due to the Python having mutuable and being
(call-by-sharing)[https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing],
it is possible to have recursive data structure, that is, data structures that
contain themselves.
This could be seen in some complex object structures where composition is
heavily used and components are tightly connected.
"""
# Recursive Lists
a = [] # Typical Empty list
a.append(a) # Addind the list to itself - a => [[...]]
a == a # A list is equal to itself
a == a[0] # A list is equal to its first argument
a == a[0][0] # A list is equal to the first argument of its first argument
a == a[0][0][0] # And so on..
# Same applies with dictionaries
a = {}
a["a"] = a
a == a
a == a["a"]
a == a["a"]["a"]
a == a["a"]["a"]["a"]
# Data Structures could be mutually nested
b = {}
a = [b]
b["a"] = a
a == a
a[0] == b
a[0]['a'] == a
b == b
b['a'] == a
b['a'][0] == b