Skip to content

Commit 70132a3

Browse files
committed
ch11: sample code
1 parent 5a4065c commit 70132a3

14 files changed

+946
-0
lines changed

11-pythonic-obj/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# The Python Data Model
2+
3+
Sample code for Chapter 11 of _Fluent Python 2e_ by Luciano Ramalho (O'Reilly, 2020)

11-pythonic-obj/mem_test.py

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import importlib
2+
import sys
3+
import resource
4+
5+
NUM_VECTORS = 10**7
6+
7+
if len(sys.argv) == 2:
8+
module_name = sys.argv[1].replace('.py', '')
9+
module = importlib.import_module(module_name)
10+
else:
11+
print('Usage: {} <vector-module-to-test>'.format())
12+
sys.exit(1)
13+
14+
fmt = 'Selected Vector2d type: {.__name__}.{.__name__}'
15+
print(fmt.format(module, module.Vector2d))
16+
17+
mem_init = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
18+
print('Creating {:,} Vector2d instances'.format(NUM_VECTORS))
19+
20+
vectors = [module.Vector2d(3.0, 4.0) for i in range(NUM_VECTORS)]
21+
22+
mem_final = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
23+
print('Initial RAM usage: {:14,}'.format(mem_init))
24+
print(' Final RAM usage: {:14,}'.format(mem_final))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public class Confidential {
2+
3+
private String secret = "";
4+
5+
public Confidential(String text) {
6+
secret = text.toUpperCase();
7+
}
8+
}

11-pythonic-obj/private/Expose.java

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import java.lang.reflect.Field;
2+
3+
public class Expose {
4+
5+
public static void main(String[] args) {
6+
Confidential message = new Confidential("top secret text");
7+
Field secretField = null;
8+
try {
9+
secretField = Confidential.class.getDeclaredField("secret");
10+
}
11+
catch (NoSuchFieldException e) {
12+
System.err.println(e);
13+
System.exit(1);
14+
}
15+
secretField.setAccessible(true); // break the lock!
16+
try {
17+
String wasHidden = (String) secretField.get(message);
18+
System.out.println("message.secret = " + wasHidden);
19+
}
20+
catch (IllegalAccessException e) {
21+
// this will not happen after setAcessible(true)
22+
System.err.println(e);
23+
}
24+
}
25+
}

11-pythonic-obj/private/expose.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Confidential
2+
3+
message = Confidential('top secret text')
4+
secret_field = Confidential.getDeclaredField('secret')
5+
secret_field.setAccessible(True) # break the lock!
6+
print 'message.secret =', secret_field.get(message)
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from java.lang.reflect import Modifier
2+
import Confidential
3+
4+
message = Confidential('top secret text')
5+
fields = Confidential.getDeclaredFields()
6+
for field in fields:
7+
# list private fields only
8+
if Modifier.isPrivate(field.getModifiers()):
9+
field.setAccessible(True) # break the lock
10+
print 'field:', field
11+
print '\t', field.getName(), '=', field.get(message)

11-pythonic-obj/private/no_respect.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
"""
3+
In the Jython registry file there is this line:
4+
5+
python.security.respectJavaAccessibility = true
6+
7+
Set this to false and Jython provides access to non-public
8+
fields, methods, and constructors of Java objects.
9+
"""
10+
11+
import Confidential
12+
13+
message = Confidential('top secret text')
14+
for name in dir(message):
15+
attr = getattr(message, name)
16+
if not callable(attr): # non-methods only
17+
print name + '\t=', attr

11-pythonic-obj/vector2d_v0.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
A 2-dimensional vector class
3+
4+
# tag::VECTOR2D_V0_DEMO[]
5+
6+
>>> v1 = Vector2d(3, 4)
7+
>>> print(v1.x, v1.y) # <1>
8+
3.0 4.0
9+
>>> x, y = v1 # <2>
10+
>>> x, y
11+
(3.0, 4.0)
12+
>>> v1 # <3>
13+
Vector2d(3.0, 4.0)
14+
>>> v1_clone = eval(repr(v1)) # <4>
15+
>>> v1 == v1_clone # <5>
16+
True
17+
>>> print(v1) # <6>
18+
(3.0, 4.0)
19+
>>> octets = bytes(v1) # <7>
20+
>>> octets
21+
b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'
22+
>>> abs(v1) # <8>
23+
5.0
24+
>>> bool(v1), bool(Vector2d(0, 0)) # <9>
25+
(True, False)
26+
27+
# end::VECTOR2D_V0_DEMO[]
28+
"""
29+
30+
# tag::VECTOR2D_V0[]
31+
from array import array
32+
import math
33+
34+
35+
class Vector2d:
36+
typecode = 'd' # <1>
37+
38+
def __init__(self, x, y):
39+
self.x = float(x) # <2>
40+
self.y = float(y)
41+
42+
def __iter__(self):
43+
return (i for i in (self.x, self.y)) # <3>
44+
45+
def __repr__(self):
46+
class_name = type(self).__name__
47+
return '{}({!r}, {!r})'.format(class_name, *self) # <4>
48+
49+
def __str__(self):
50+
return str(tuple(self)) # <5>
51+
52+
def __bytes__(self):
53+
return (bytes([ord(self.typecode)]) + # <6>
54+
bytes(array(self.typecode, self))) # <7>
55+
56+
def __eq__(self, other):
57+
return tuple(self) == tuple(other) # <8>
58+
59+
def __abs__(self):
60+
return math.hypot(self.x, self.y) # <9>
61+
62+
def __bool__(self):
63+
return bool(abs(self)) # <10>
64+
# end::VECTOR2D_V0[]

11-pythonic-obj/vector2d_v1.py

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""
2+
A 2-dimensional vector class
3+
4+
>>> v1 = Vector2d(3, 4)
5+
>>> print(v1.x, v1.y)
6+
3.0 4.0
7+
>>> x, y = v1
8+
>>> x, y
9+
(3.0, 4.0)
10+
>>> v1
11+
Vector2d(3.0, 4.0)
12+
>>> v1_clone = eval(repr(v1))
13+
>>> v1 == v1_clone
14+
True
15+
>>> print(v1)
16+
(3.0, 4.0)
17+
>>> octets = bytes(v1)
18+
>>> octets
19+
b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'
20+
>>> abs(v1)
21+
5.0
22+
>>> bool(v1), bool(Vector2d(0, 0))
23+
(True, False)
24+
25+
26+
Test of ``.frombytes()`` class method:
27+
28+
>>> v1_clone = Vector2d.frombytes(bytes(v1))
29+
>>> v1_clone
30+
Vector2d(3.0, 4.0)
31+
>>> v1 == v1_clone
32+
True
33+
34+
"""
35+
36+
from array import array
37+
import math
38+
39+
40+
class Vector2d:
41+
typecode = 'd'
42+
43+
def __init__(self, x, y):
44+
self.x = float(x)
45+
self.y = float(y)
46+
47+
def __iter__(self):
48+
return (i for i in (self.x, self.y))
49+
50+
def __repr__(self):
51+
class_name = type(self).__name__
52+
return '{}({!r}, {!r})'.format(class_name, *self)
53+
54+
def __str__(self):
55+
return str(tuple(self))
56+
57+
def __bytes__(self):
58+
return (bytes([ord(self.typecode)]) +
59+
bytes(array(self.typecode, self)))
60+
61+
def __eq__(self, other):
62+
return tuple(self) == tuple(other)
63+
64+
def __abs__(self):
65+
return math.hypot(self.x, self.y)
66+
67+
def __bool__(self):
68+
return bool(abs(self))
69+
70+
# tag::VECTOR2D_V1[]
71+
@classmethod # <1>
72+
def frombytes(cls, octets): # <2>
73+
typecode = chr(octets[0]) # <3>
74+
memv = memoryview(octets[1:]).cast(typecode) # <4>
75+
return cls(*memv) # <5>
76+
# end::VECTOR2D_V1[]

11-pythonic-obj/vector2d_v2.py

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
"""
2+
A 2-dimensional vector class
3+
4+
>>> v1 = Vector2d(3, 4)
5+
>>> print(v1.x, v1.y)
6+
3.0 4.0
7+
>>> x, y = v1
8+
>>> x, y
9+
(3.0, 4.0)
10+
>>> v1
11+
Vector2d(3.0, 4.0)
12+
>>> v1_clone = eval(repr(v1))
13+
>>> v1 == v1_clone
14+
True
15+
>>> print(v1)
16+
(3.0, 4.0)
17+
>>> octets = bytes(v1)
18+
>>> octets
19+
b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'
20+
>>> abs(v1)
21+
5.0
22+
>>> bool(v1), bool(Vector2d(0, 0))
23+
(True, False)
24+
25+
26+
Test of ``.frombytes()`` class method:
27+
28+
>>> v1_clone = Vector2d.frombytes(bytes(v1))
29+
>>> v1_clone
30+
Vector2d(3.0, 4.0)
31+
>>> v1 == v1_clone
32+
True
33+
34+
35+
Tests of ``format()`` with Cartesian coordinates:
36+
37+
>>> format(v1)
38+
'(3.0, 4.0)'
39+
>>> format(v1, '.2f')
40+
'(3.00, 4.00)'
41+
>>> format(v1, '.3e')
42+
'(3.000e+00, 4.000e+00)'
43+
44+
45+
Tests of the ``angle`` method::
46+
47+
>>> Vector2d(0, 0).angle()
48+
0.0
49+
>>> Vector2d(1, 0).angle()
50+
0.0
51+
>>> epsilon = 10**-8
52+
>>> abs(Vector2d(0, 1).angle() - math.pi/2) < epsilon
53+
True
54+
>>> abs(Vector2d(1, 1).angle() - math.pi/4) < epsilon
55+
True
56+
57+
58+
Tests of ``format()`` with polar coordinates:
59+
60+
>>> format(Vector2d(1, 1), 'p') # doctest:+ELLIPSIS
61+
'<1.414213..., 0.785398...>'
62+
>>> format(Vector2d(1, 1), '.3ep')
63+
'<1.414e+00, 7.854e-01>'
64+
>>> format(Vector2d(1, 1), '0.5fp')
65+
'<1.41421, 0.78540>'
66+
67+
"""
68+
69+
# BEGIN VECTOR2D_V2
70+
from array import array
71+
import math
72+
73+
74+
class Vector2d:
75+
typecode = 'd'
76+
77+
def __init__(self, x, y):
78+
self.x = float(x)
79+
self.y = float(y)
80+
81+
def __iter__(self):
82+
return (i for i in (self.x, self.y))
83+
84+
def __repr__(self):
85+
class_name = type(self).__name__
86+
return '{}({!r}, {!r})'.format(class_name, *self)
87+
88+
def __str__(self):
89+
return str(tuple(self))
90+
91+
def __bytes__(self):
92+
return (bytes([ord(self.typecode)]) +
93+
bytes(array(self.typecode, self)))
94+
95+
def __eq__(self, other):
96+
return tuple(self) == tuple(other)
97+
98+
def __abs__(self):
99+
return math.hypot(self.x, self.y)
100+
101+
def __bool__(self):
102+
return bool(abs(self))
103+
104+
def angle(self):
105+
return math.atan2(self.y, self.x)
106+
107+
def __format__(self, fmt_spec=''):
108+
if fmt_spec.endswith('p'):
109+
fmt_spec = fmt_spec[:-1]
110+
coords = (abs(self), self.angle())
111+
outer_fmt = '<{}, {}>'
112+
else:
113+
coords = self
114+
outer_fmt = '({}, {})'
115+
components = (format(c, fmt_spec) for c in coords)
116+
return outer_fmt.format(*components)
117+
118+
@classmethod
119+
def frombytes(cls, octets):
120+
typecode = chr(octets[0])
121+
memv = memoryview(octets[1:]).cast(typecode)
122+
return cls(*memv)
123+
# END VECTOR2D_V2

0 commit comments

Comments
 (0)