-
Notifications
You must be signed in to change notification settings - Fork 47
Expand file tree
/
Copy pathelement_generic.py
More file actions
128 lines (99 loc) · 3.35 KB
/
element_generic.py
File metadata and controls
128 lines (99 loc) · 3.35 KB
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
from functools import singledispatchmethod
class Element:
__slots__ = (
'name',
'number',
'symbol',
'__weakref__',
)
def __init__(self, symbol, number, name):
self.symbol = symbol.title()
self.number = number
self.name = name.lower()
def __repr__(self):
return f"{self.symbol} ({self.name}): {self.number}"
def __str__(self):
return self.symbol
def __hash__(self):
return hash(self.symbol)
@singledispatchmethod
def __eq__(self, other):
return self.symbol == other.symbol
@__eq__.register
def _(self, other: str):
return self.symbol == other
@__eq__.register
def _(self, other: float):
return self.number == other
@__eq__.register
def _(self, other: int):
return self.number == other
@singledispatchmethod
def __lt__(self, other):
return self.symbol < other.symbol
@__lt__.register(str)
def _(self, other):
return self.symbol < other
@__lt__.register(int)
@__lt__.register(float)
def _(self, other):
return self.number < other
@singledispatchmethod
def __le__(self, other):
return self.symbol <= other.symbol
__le__.register(str, lambda self, other: self.symbol <= other)
__le__.register(int, lambda self, other: self.number <= other)
__le__.register(float, lambda self, other: self.number <= other)
def __selfattr__(self, name, value):
if hasattr(self, name):
raise AttributeError(
f"'{type(self)}' object attribute '{name}' is read-only"
)
object.__setattr__(self, name, value)
def __delattr__(self, name):
raise AttributeError(
f"'{type(self)}' object attribute '{name}' is read-only"
)
class Compound:
def __init__(self, name):
self.name = name.title()
self.components = {}
def add_element(self, element, count):
try:
self.components[element] += count
except KeyError:
self.components[element] = count
def __str__(self):
s = ""
formula = self.components.copy()
# Hill system
if 'C' in formula.keys():
s += f"C{formula['C']}"
del formula['C']
if 'H' in formula.keys():
s += f"H{formula['H']}"
del formula['H']
for element, count in sorted(formula.items()):
s += f"{element.symbol}{count if count > 1 else ''}"
# substitute subscript digits for normal digits
s = s.translate(str.maketrans("0123456789","₀₁₂₃₄₅₆₇₈₉"))
return s
def __repr__(self):
return f"{self.name}: {self}"
hydrogen = Element('H', 1, 'hydrogen')
carbon = Element('C', 6, 'carbon')
oxygen = Element('O', 8, 'oxygen')
iron = Element('Fe', 26, 'iron')
rust = Compound("iron oxide")
rust.add_element(oxygen, count=3)
rust.add_element(iron, count=2)
print(f"{rust!r}") # prints 'Iron Oxide: Fe₂O₃'
aspirin = Compound("acetylsalicylic acid")
aspirin.add_element(hydrogen, 8)
aspirin.add_element(oxygen, 4)
aspirin.add_element(carbon, 9)
print(f"{aspirin!r}") # prints 'Acetylsalicylic Acid: C₉H₈O₄'
water = Compound("water")
water.add_element(hydrogen, 2)
water.add_element(oxygen, 1)
print(f"{water!r}") # prints 'Water: H₂O'