Skip to content

Commit 7582d52

Browse files
committed
8.11-8.19小节完成
1 parent 65e1945 commit 7582d52

18 files changed

+2247
-28
lines changed

cookbook/c08/p11_simplify_init.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
"""
4+
Topic: 简化数据结构的初始化
5+
Desc :
6+
"""
7+
import math
8+
9+
10+
class Structure1:
11+
# Class variable that specifies expected fields
12+
_fields = []
13+
14+
def __init__(self, *args):
15+
if len(args) != len(self._fields):
16+
raise TypeError('Expected {} arguments'.format(len(self._fields)))
17+
# Set the arguments
18+
for name, value in zip(self._fields, args):
19+
setattr(self, name, value)
20+
21+
# Example class definitions
22+
if __name__ == '__main__':
23+
class Stock(Structure1):
24+
_fields = ['name', 'shares', 'price']
25+
26+
class Point(Structure1):
27+
_fields = ['x', 'y']
28+
29+
class Circle(Structure1):
30+
_fields = ['radius']
31+
32+
def area(self):
33+
return math.pi * self.radius ** 2
34+
35+
s = Stock('ACME', 50, 91.1)
36+
p = Point(2, 3)
37+
c = Circle(4.5)
38+
39+
40+
class Structure2:
41+
_fields = []
42+
43+
def __init__(self, *args, **kwargs):
44+
if len(args) > len(self._fields):
45+
raise TypeError('Expected {} arguments'.format(len(self._fields)))
46+
47+
# Set all of the positional arguments
48+
for name, value in zip(self._fields, args):
49+
setattr(self, name, value)
50+
51+
# Set the remaining keyword arguments
52+
for name in self._fields[len(args):]:
53+
setattr(self, name, kwargs.pop(name))
54+
55+
# Check for any remaining unknown arguments
56+
if kwargs:
57+
raise TypeError('Invalid argument(s): {}'.format(','.join(kwargs)))
58+
59+
# Example use
60+
if __name__ == '__main__':
61+
class Stock(Structure2):
62+
_fields = ['name', 'shares', 'price']
63+
64+
s1 = Stock('ACME', 50, 91.1)
65+
s2 = Stock('ACME', 50, price=91.1)
66+
s3 = Stock('ACME', shares=50, price=91.1)
67+
# s3 = Stock('ACME', shares=50, price=91.1, aa=1)
68+
69+
70+
class Structure3:
71+
# Class variable that specifies expected fields
72+
_fields = []
73+
74+
def __init__(self, *args, **kwargs):
75+
if len(args) != len(self._fields):
76+
raise TypeError('Expected {} arguments'.format(len(self._fields)))
77+
78+
# Set the arguments
79+
for name, value in zip(self._fields, args):
80+
setattr(self, name, value)
81+
82+
# Set the additional arguments (if any)
83+
extra_args = kwargs.keys() - self._fields
84+
for name in extra_args:
85+
setattr(self, name, kwargs.pop(name))
86+
87+
if kwargs:
88+
raise TypeError('Duplicate values for {}'.format(','.join(kwargs)))
89+
90+
# Example use
91+
if __name__ == '__main__':
92+
class Stock(Structure3):
93+
_fields = ['name', 'shares', 'price']
94+
95+
s1 = Stock('ACME', 50, 91.1)
96+
s2 = Stock('ACME', 50, 91.1, date='8/2/2012')
97+
98+
99+
class Structure4:
100+
# Class variable that specifies expected fields
101+
_fields= []
102+
def __init__(self, *args):
103+
if len(args) != len(self._fields):
104+
raise TypeError('Expected {} arguments'.format(len(self._fields)))
105+
106+
# Set the arguments (alternate)
107+
self.__dict__.update(zip(self._fields,args))
108+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
"""
4+
Topic: 定义接口或抽象类
5+
Desc :
6+
"""
7+
from abc import ABCMeta, abstractmethod
8+
9+
10+
class IStream(metaclass=ABCMeta):
11+
@abstractmethod
12+
def read(self, maxbytes=-1):
13+
pass
14+
15+
@abstractmethod
16+
def write(self, data):
17+
pass
18+
19+
20+
class SocketStream(IStream):
21+
def read(self, maxbytes=-1):
22+
pass
23+
24+
def write(self, data):
25+
pass
26+
27+
28+
class A(metaclass=ABCMeta):
29+
@property
30+
@abstractmethod
31+
def name(self):
32+
pass
33+
34+
@name.setter
35+
@abstractmethod
36+
def name(self, value):
37+
pass
38+
39+
@classmethod
40+
@abstractmethod
41+
def method1(cls):
42+
pass
43+
44+
@staticmethod
45+
@abstractmethod
46+
def method2():
47+
pass
48+

cookbook/c08/p13_type_system.py

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
"""
4+
Topic: 类型检查系统
5+
Desc :
6+
"""
7+
8+
9+
# Base class. Uses a descriptor to set a value
10+
class Descriptor:
11+
def __init__(self, name=None, **opts):
12+
self.name = name
13+
for key, value in opts.items():
14+
setattr(self, key, value)
15+
16+
def __set__(self, instance, value):
17+
instance.__dict__[self.name] = value
18+
19+
20+
# Descriptor for enforcing types
21+
class Typed(Descriptor):
22+
expected_type = type(None)
23+
24+
def __set__(self, instance, value):
25+
if not isinstance(value, self.expected_type):
26+
raise TypeError('expected ' + str(self.expected_type))
27+
super().__set__(instance, value)
28+
29+
30+
# Descriptor for enforcing values
31+
class Unsigned(Descriptor):
32+
def __set__(self, instance, value):
33+
if value < 0:
34+
raise ValueError('Expected >= 0')
35+
super().__set__(instance, value)
36+
37+
38+
class MaxSized(Descriptor):
39+
def __init__(self, name=None, **opts):
40+
if 'size' not in opts:
41+
raise TypeError('missing size option')
42+
super().__init__(name, **opts)
43+
44+
def __set__(self, instance, value):
45+
if len(value) >= self.size:
46+
raise ValueError('size must be < ' + str(self.size))
47+
super().__set__(instance, value)
48+
49+
50+
if __name__ == '__main__':
51+
class Integer(Typed):
52+
expected_type = int
53+
54+
class UnsignedInteger(Integer, Unsigned):
55+
pass
56+
57+
class Float(Typed):
58+
expected_type = float
59+
60+
class UnsignedFloat(Float, Unsigned):
61+
pass
62+
63+
class String(Typed):
64+
expected_type = str
65+
66+
class SizedString(String, MaxSized):
67+
pass
68+
69+
class Stock:
70+
# Specify constraints
71+
name = SizedString('name', size=8)
72+
shares = UnsignedInteger('shares')
73+
price = UnsignedFloat('price')
74+
75+
def __init__(self, name, shares, price):
76+
self.name = name
77+
self.shares = shares
78+
self.price = price
79+
80+
s = Stock('ACME', 50, 91.1)
81+
82+
# Class decorator to apply constraints
83+
def check_attributes(**kwargs):
84+
def decorate(cls):
85+
for key, value in kwargs.items():
86+
if isinstance(value, Descriptor):
87+
value.name = key
88+
setattr(cls, key, value)
89+
else:
90+
setattr(cls, key, value(key))
91+
return cls
92+
93+
return decorate
94+
95+
# Example
96+
@check_attributes(name=SizedString(size=8),
97+
shares=UnsignedInteger,
98+
price=UnsignedFloat)
99+
class Stock:
100+
def __init__(self, name, shares, price):
101+
self.name = name
102+
self.shares = shares
103+
self.price = price
104+
105+
106+
107+
# A metaclass that applies checking
108+
class checkedmeta(type):
109+
def __new__(cls, clsname, bases, methods):
110+
# Attach attribute names to the descriptors
111+
for key, value in methods.items():
112+
if isinstance(value, Descriptor):
113+
value.name = key
114+
return type.__new__(cls, clsname, bases, methods)
115+
116+
117+
# Example
118+
class Stock2(metaclass=checkedmeta):
119+
name = SizedString(size=8)
120+
shares = UnsignedInteger()
121+
price = UnsignedFloat()
122+
123+
def __init__(self, name, shares, price):
124+
self.name = name
125+
self.shares = shares
126+
self.price = price
127+
128+
129+
# Base class. Uses a descriptor to set a value
130+
class Descriptor:
131+
def __init__(self, name=None, **opts):
132+
self.name = name
133+
for key, value in opts.items():
134+
setattr(self, key, value)
135+
136+
def __set__(self, instance, value):
137+
instance.__dict__[self.name] = value
138+
139+
140+
# Decorator for applying type checking
141+
def Typed(expected_type, cls=None):
142+
if cls is None:
143+
return lambda cls: Typed(expected_type, cls)
144+
super_set = cls.__set__
145+
146+
def __set__(self, instance, value):
147+
if not isinstance(value, expected_type):
148+
raise TypeError('expected ' + str(expected_type))
149+
super_set(self, instance, value)
150+
151+
cls.__set__ = __set__
152+
return cls
153+
154+
155+
# Decorator for unsigned values
156+
def Unsigned(cls):
157+
super_set = cls.__set__
158+
159+
def __set__(self, instance, value):
160+
if value < 0:
161+
raise ValueError('Expected >= 0')
162+
super_set(self, instance, value)
163+
164+
cls.__set__ = __set__
165+
return cls
166+
167+
168+
# Decorator for allowing sized values
169+
def MaxSized(cls):
170+
super_init = cls.__init__
171+
172+
def __init__(self, name=None, **opts):
173+
if 'size' not in opts:
174+
raise TypeError('missing size option')
175+
super_init(self, name, **opts)
176+
177+
cls.__init__ = __init__
178+
179+
super_set = cls.__set__
180+
181+
def __set__(self, instance, value):
182+
if len(value) >= self.size:
183+
raise ValueError('size must be < ' + str(self.size))
184+
super_set(self, instance, value)
185+
186+
cls.__set__ = __set__
187+
return cls
188+
189+
190+
# Specialized descriptors
191+
@Typed(int)
192+
class Integer(Descriptor):
193+
pass
194+
195+
196+
@Unsigned
197+
class UnsignedInteger(Integer):
198+
pass
199+
200+
201+
@Typed(float)
202+
class Float(Descriptor):
203+
pass
204+
205+
206+
@Unsigned
207+
class UnsignedFloat(Float):
208+
pass
209+
210+
211+
@Typed(str)
212+
class String(Descriptor):
213+
pass
214+
215+
216+
@MaxSized
217+
class SizedString(String):
218+
pass

0 commit comments

Comments
 (0)