-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathNamedTuple.py
127 lines (100 loc) · 3.91 KB
/
NamedTuple.py
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
from collections import namedtuple
def NamedTuple(name, *slots):
class cls(namedtuple(name, slots)):
@classmethod
def new(cls, *values):
return cls._make(values)
@property
def values(self):
return tuple.__iter__(self)
def alter(self, **kargs):
return self._replace(**kargs)
@property
def named_values(self):
return ((self._fields[index], value) for (index, value) in enumerate(self.values))
@classmethod
def from_named_valeus(cls, named_values):
return cls.from_dict(dict(named_values))
@classmethod
def from_dict(cls, dct, default = None):
return cls.new(*(dct.get(slot, default) for slot in cls._fields))
@classmethod
def make_setter(cls, index):
return lambda self, value: self.set_by_index(index, value)
def set_by_index(self, set_index, set_value):
return self._make((set_value if set_index == index else value
for (index, value)
in enumerate(self.values)))
for index, slot in enumerate(slots):
setattr(cls, "set_" + slot, cls.make_setter(index))
cls.__name__ = name
return cls
def upper_first(string):
return string[0].upper() + string[1:]
class LinkedList(NamedTuple("LinkedList", "first", "rest")):
def __new__(cls, first, rest = None):
return cls.new(first, rest)
# doesn't work with namedtuple :(
#def __getitem__(self, index):
# return iget(self, index)
def __iter__(rest):
while True:
first, rest = rest.values
yield first
if rest is None:
raise StopIteration
def cons(self, value):
return self.new(value, self)
if __name__ == "__main__":
# tests
def err(code, err_type = Exception):
try:
code()
except err_type, error:
return error
Person = NamedTuple("Person", "name", "age")
name = "peter"
age = 25
peter = Person(name, age)
assert peter.name == name
assert peter[0] == name
assert peter.age == age
assert peter[1] == age
assert tuple(peter.values) == (name, age)
assert tuple(peter) == (name, age)
assert list(peter.named_values) == [("name", name), ("age", age)]
assert peter == Person("peter", 25)
#assert repr(peter) == "Person('peter', 25)"
assert peter == Person.from_named_valeus(peter.named_values)
assert peter == Person.from_dict(dict(peter.named_values))
assert err(lambda : peter.height, AttributeError)
assert err(lambda : peter[2], IndexError)
assert err(lambda : Person())
assert err(lambda : Person("peter"))
assert peter.alter(age = 29) == Person(name, 29)
assert peter.set_age(29) == Person(name, 29)
assert peter.alter(name = "grandpa", age = 99) == Person("grandpa", 99)
assert peter.set_name("grandpa").set_age(99) == Person("grandpa", 99)
def iget(itr, index):
try:
itr = iter(itr)
for _ in xrange(index):
itr.next()
return itr.next()
except StopIteration:
raise IndexError
names1 = LinkedList("alice")
names2 = names1.cons("bob")
names2z = names1.cons("zed")
names3 = names2.cons("charlie")
assert list(names1) == ["alice"]
assert list(names2) == ["bob", "alice"]
assert list(names2z) == ["zed", "alice"]
assert list(names3) == ["charlie", "bob", "alice"]
# doesn't work with namedtuple :(
#assert names3[1] == "bob"
#assert names3[0] == "charlie"
assert err(lambda : names3[3], IndexError)
assert names3.first == "charlie"
assert (names3.first, list(names3.rest)) == ("charlie", ["bob", "alice"])
print "passed!"