1 class Descriptor:
2 def __init__(self, name=None, **opts):
3 self.name = name
4 for key, value in opts.items():
5 setattr(self, key, value)
6
7 def __set__(self, instance, value):
8 instance.__dict__[self.name] = value
9
10
11 # Descriptor for enforcing types
12 class Typed(Descriptor):
13 expected_type = type(None)
14
15 def __set__(self, instance, value):
16 if not isinstance(value, self.expected_type):
17 raise TypeError('expected ' + str(self.expected_type))
18 super().__set__(instance, value)
19
20
21 # Descriptor for enforcing values
22 class Unsigned(Descriptor):
23 def __set__(self, instance, value):
24 if value < 0:
25 raise ValueError('Expected >= 0')
26 super().__set__(instance, value)
27
28
29 class MaxSized(Descriptor):
30 def __init__(self, name=None, **opts):
31 if 'size' not in opts:
32 raise TypeError('missing size option')
33 super().__init__(name, **opts)
34
35 def __set__(self, instance, value):
36 if len(value) >= self.size:
37 raise ValueError('size must be < ' + str(self.size))
38 super().__set__(instance, value)
39
40 class Integer(Typed):
41 expected_type = int # 将上面的赋值覆盖了
42
43 class UnsignedInteger(Integer, Unsigned):
44 pass
45
46 class Float(Typed):
47 expected_type = float
48
49 class UnsignedFloat(Float, Unsigned):
50 pass
51
52 class String(Typed):
53 expected_type = str
54
55 class SizedString(String, MaxSized):
56 pass
57
58
59 class Stock:
60 # Specify constraints
61 name = SizedString('name', size=8)
62 shares = UnsignedInteger('shares')
63 price = UnsignedFloat('price')
64
65 def __init__(self, name, shares, price):
66 self.name = name
67 self.shares = shares
68 self.price = price
69
70 s=Stock('sdf',23,4.3)
71 # s.shares = 2.3
72 s.shares=-10