Skip to content

Commit 4ff8f14

Browse files
committed
More codeblocks
1 parent 9a9ff92 commit 4ff8f14

File tree

3 files changed

+357
-6
lines changed

3 files changed

+357
-6
lines changed

app/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
import sys
66

77
from app.codeblocks import get_func_body
8-
from app.pages import first_steps, first_projects, variables
8+
from app.pages import first_steps, first_projects, variables, classes
99
from app.qa import CodeblocksTester, BuildTestFailure
1010

1111

1212
PAGE_MODULES = (
1313
first_steps,
1414
first_projects,
1515
variables,
16+
classes,
1617
)
1718

1819
OUTPUT_DIR = "dist"

app/pages/classes.py

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
"""23_classes.md"""
2+
# pylint: disable=line-too-long
3+
# pylint: disable=missing-class-docstring
4+
# pylint: disable=missing-function-docstring
5+
# pylint: disable=too-few-public-methods
6+
# pylint: disable=unused-variable
7+
# pylint: disable=import-outside-toplevel
8+
9+
10+
def first_class():
11+
"""
12+
>>> MyType = first_class()
13+
>>> MyType.class_attribute
14+
0
15+
>>> MyType.regular_attribute
16+
Traceback (most recent call last):
17+
...
18+
AttributeError: type object 'MyType' has no attribute 'regular_attribute'
19+
>>> instance_1 = MyType(42)
20+
>>> instance_1.instance, instance_1.class_attribute
21+
(1, 1)
22+
>>> MyType.class_attribute
23+
1
24+
>>> instance_1.regular_attribute
25+
42
26+
>>> instance_1.regular_attribute = -700
27+
>>> instance_1.regular_attribute
28+
-700
29+
>>> instance_2 = MyType(13)
30+
>>> instance_2.instance, instance_2.class_attribute
31+
(2, 2)
32+
>>> instance_1.my_method()
33+
Instance: 1, Regular Attribute: -700
34+
>>> instance_2.regular_attribute
35+
13
36+
"""
37+
# START
38+
class MyType:
39+
class_attribute = 0
40+
def __init__(self, arg):
41+
self.regular_attribute = arg
42+
MyType.class_attribute += 1
43+
self.instance = MyType.class_attribute
44+
45+
def my_method(self):
46+
print(f"Instance: {self.instance}, Regular Attribute: {self.regular_attribute}")
47+
# END
48+
return MyType
49+
50+
51+
def person_class():
52+
"""
53+
>>> Person = person_class()
54+
>>> person_1 = Person("Bill", 33)
55+
>>> person_2 = Person(name="Jill", age=44)
56+
>>> person_1.name, person_1.age
57+
('Bill', 33)
58+
>>> person_2.name, person_2.age
59+
('Jill', 44)
60+
>>> person_1.greet(person_2)
61+
Hello, Jill, my name is Bill!
62+
>>> person_1.birthday()
63+
>>> person_1.age
64+
34
65+
"""
66+
# START
67+
class Person:
68+
def __init__(self, name, age):
69+
self.name = name
70+
self.age = age
71+
72+
def greet(self, person):
73+
print(f'Hello, {person.name}, my name is {self.name}!')
74+
75+
def birthday(self):
76+
self.age += 1
77+
# END
78+
return Person
79+
80+
81+
def class_dunder_eq():
82+
"""
83+
>>> Foo = class_dunder_eq()
84+
>>> f1 = Foo(13)
85+
>>> f2 = Foo(42)
86+
>>> f3 = Foo(13)
87+
>>> f4 = f3
88+
>>> f1 == f2
89+
False
90+
>>> f1 == f3
91+
True
92+
>>> f1 is f3
93+
False
94+
>>> f3 is f4
95+
True
96+
"""
97+
# START
98+
class Foo:
99+
def __init__(self, value):
100+
self.value = value
101+
102+
def __eq__(self, other):
103+
return self.value == other.value
104+
# END
105+
return Foo
106+
107+
108+
def callable_type():
109+
"""
110+
>>> CallableType = callable_type()
111+
>>> c = CallableType()
112+
>>> c()
113+
You rang?
114+
"""
115+
# START
116+
class CallableType:
117+
def __call__(self):
118+
print("You rang?")
119+
# END
120+
return CallableType
121+
122+
123+
def context_manager_type():
124+
"""
125+
>>> ContextManagerType = context_manager_type()
126+
>>> c = ContextManagerType()
127+
>>> with c as bound_var:
128+
... print(bound_var)
129+
setup! here's a foo!
130+
foo
131+
cleanup!
132+
"""
133+
# START
134+
class ContextManagerType:
135+
def __enter__(self):
136+
print("setup! here's a foo!")
137+
return "foo"
138+
def __exit__(self, *args, **kwargs):
139+
print("cleanup!")
140+
# END
141+
return ContextManagerType
142+
143+
144+
def enum_ints():
145+
"""
146+
>>> StoplightColors = enum_ints()
147+
>>> StoplightColors.YELLOW
148+
<StoplightColors.YELLOW: 2>
149+
>>> StoplightColors.YELLOW.value
150+
2
151+
"""
152+
# START
153+
from enum import Enum
154+
155+
# The below syntax represents inheritance
156+
# This means that our class StoplightColors has all of the properties
157+
# of the Enum class
158+
class StoplightColors(Enum):
159+
# You must assign an integer to each enumerated value
160+
GREEN = 1
161+
YELLOW = 2
162+
RED = 3
163+
# END
164+
return StoplightColors
165+
166+
def enum_str():
167+
"""
168+
>>> StoplightColors = enum_str()
169+
>>> StoplightColors.GREEN
170+
<StoplightColors.GREEN: 'green'>
171+
>>> StoplightColors.GREEN.value
172+
'green'
173+
"""
174+
from enum import Enum
175+
# START
176+
# The below syntax represents multiple inheritance
177+
# This gives the properties of both str and Enum to our class
178+
# This may be useful if we want to retrieve a string value instead of an integer value
179+
# Python 3.11 adds a StrEnum class that you can import that gives this functionality with a few extra features.
180+
class StoplightColors(str, Enum):
181+
GREEN = 'green'
182+
YELLOW = 'yellow'
183+
RED = 'red'
184+
# END
185+
return StoplightColors
186+
187+
188+
def dataclasses():
189+
"""
190+
>>> dataclasses()
191+
"""
192+
from dataclasses import dataclass
193+
194+
@dataclass
195+
class Person:
196+
name: str
197+
age: int = 0

app/pages/variables.py

Lines changed: 158 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
from unittest.mock import patch
21
# pylint: disable=line-too-long
3-
# pylint: disable=redefined-builtin
4-
5-
6-
NONLOCALS = ("patch",)
72

83

94
def variables_assignments():
@@ -35,3 +30,161 @@ def do_something(v1, v2):
3530
do_something(var_1, var_2)
3631
# END
3732

33+
34+
def variables_underscore_as_unused():
35+
"""
36+
>>> variables_underscore_as_unused()
37+
hello
38+
hello
39+
hello
40+
"""
41+
# we don't need the numbers in the range, we just want to do an action n times
42+
for _ in range(3):
43+
print("hello")
44+
45+
def returns_two():
46+
return 3, 'foo'
47+
48+
# we do not intend to use the first element of the returned tuple
49+
_, my_var = returns_two()
50+
51+
52+
def variables_scope():
53+
"""
54+
>>> try:
55+
... variables_scope()
56+
... except NameError:
57+
... pass
58+
2
59+
"""
60+
var_1 = 2
61+
def func_1():
62+
# functions have their own scope
63+
var_2 = 3
64+
65+
print(var_1) # 2
66+
print(var_2) # NameError
67+
68+
69+
def variables_block_scope_good():
70+
"""
71+
>>> variables_block_scope_good()
72+
100.13
73+
"""
74+
if True:
75+
var_1 = 100.13
76+
else:
77+
var_1 = -33.12
78+
print(var_1) # 100.13
79+
80+
81+
def variables_block_scope_bad():
82+
"""
83+
>>> try:
84+
... variables_block_scope_bad()
85+
... except UnboundLocalError:
86+
... pass
87+
do something
88+
"""
89+
if True:
90+
print("do something")
91+
else:
92+
var_1 = True
93+
print(var_1) # UnboundLocalError
94+
95+
96+
def runtime_variable_resolution():
97+
"""
98+
>>> runtime_variable_resolution()
99+
3
100+
"""
101+
i = 15
102+
def foo():
103+
print(i)
104+
i = 3
105+
foo() # 3
106+
107+
108+
def variables_mutating_outer_scope():
109+
"""
110+
>>> variables_mutating_outer_scope()
111+
9.3
112+
0.0
113+
9.3
114+
9.3
115+
116+
NOTE: THE LAST 9.3 IS INCORRECT.
117+
Here, global should be nonlocal.
118+
No pretty way to fix this.
119+
"""
120+
var_1 = 9.3
121+
122+
def func_1():
123+
# accessing variables from an outer scope works fine
124+
print(var_1)
125+
126+
func_1() # 9.3
127+
128+
def func_2():
129+
# trying to change them will not work as expected
130+
var_1 = 0.0
131+
print(var_1)
132+
133+
func_2() # 0.0
134+
print(var_1) # 9.3
135+
136+
def func_3():
137+
# the global keyword here grants the ability to modify var_1
138+
global var_1
139+
var_1 = 'foo'
140+
141+
func_3()
142+
print(var_1) # 'foo'
143+
144+
145+
def variables_nonlocal():
146+
"""
147+
>>> variables_nonlocal()
148+
42
149+
13
150+
"""
151+
def outer_func():
152+
var_1 = 42
153+
def inner_func():
154+
nonlocal var_1
155+
var_1 = 13
156+
print(var_1) # 42
157+
inner_func()
158+
print(var_1) # 13
159+
outer_func()
160+
161+
162+
def mutable_objects_no_copy():
163+
"""
164+
>>> mutable_objects_no_copy()
165+
[1, 2, 3, 4]
166+
"""
167+
list_1 = [1, 2, 3]
168+
list_2 = list_1 # this does not copy the list
169+
# both variables will reference the same list
170+
list_1.append(4)
171+
print(list_2) # [1, 2, 3, 4]
172+
173+
174+
def mutable_objects_copy():
175+
"""
176+
>>> mutable_objects_copy()
177+
[1, 2, 3]
178+
"""
179+
import copy
180+
list_1 = [1, 2, 3]
181+
list_2 = copy.copy(list_1)
182+
list_1.append(4)
183+
print(list_2) # [1, 2, 3]
184+
185+
# alternatively, you may copy a list with the following syntax:
186+
list_3 = list_1[:]
187+
188+
# dictionaries have a copy method, saving you an import
189+
dict_1 = {1: 2}
190+
dict_2 = dict_1.copy()

0 commit comments

Comments
 (0)