Skip to content

Instantly share code, notes, and snippets.

@Grumblesaur
Created November 8, 2019 20:25
Show Gist options
  • Save Grumblesaur/82e26463a4ba1587483bd8be3854ec59 to your computer and use it in GitHub Desktop.
Save Grumblesaur/82e26463a4ba1587483bd8be3854ec59 to your computer and use it in GitHub Desktop.
Making objects in Python the wrong way.
# prototypes.py -- James Murphy
# Construct arbitrary objects with default-initialized values
# and internal member dict-storage that provides javascript-like
# object prototyping.
import collections
def define(name, *args, bases=(object,), **fields):
if set(args) & set(fields.keys()):
raise ValueError('Member name(s) duplicated.')
none_init = {k : v for k, v in zip(args, len(args) * [None])}
members = {**none_init, **fields}
for key in members.keys():
if not key.isidentifier():
raise ValueError('Member name not an identifier: "{}"'.format(key))
if not isinstance(bases, collections.Iterable):
raise TypeError('Base classes not provided in iterable object.')
elif object not in bases:
bases = tuple(bases) + (object,)
def method_maker():
names = []
subscript = lambda s, k: s.__dict__[k]
equals = lambda s, o: vars(s) == vars(o)
copy = lambda s: type(s)(**s.__dict__)
representation = lambda s: '{tname}({mems})'.format(
tname=name,
mems=vars(s))
def initializer(self, dict_=None, **kw_members):
nonlocal names
new_values = kw_members if dict_ is None else dict_
names = new_values.keys()
self.__dict__ = new_values.copy()
def assign(self, key, item):
self.__dict__[key] = item
def delete(self, key):
del self.__dict__[key]
return {
'__init__' : initializer,
'__repr__' : representation,
'__eq__' : equals,
'__getitem__': subscript,
'__setitem__': assign,
'__delitem__': delete,
'copy' : copy
}
methods = method_maker()
for key in methods:
if key not in members:
members[key] = methods[key]
return type(name, bases, members)
class unit_tests():
def demo_creation():
Prototype = define('Prototype')
p = Prototype()
assert(p is not None)
assert(type(p) is Prototype)
different_name = Prototype
q = different_name()
assert(q is not None)
assert(type(q) is Prototype)
Point3D = define('Point3D', x=0, y=0, z=0)
w = Point3D()
assert(w.x == 0 and w.y == 0 and w.z == 0)
assert(w.__dict__ == {})
w = Point3D(x=1, y=2, z=3)
assert(w.x == 1 and w.y == 2 and w.z == 3)
assert(w.__dict__ != {})
return True
def demo_manipulation():
Prototype = define('Prototype')
p = Prototype()
assert(not hasattr(p, 'x'))
p.x = 1
assert(hasattr(p, 'x'))
Point2D = define('Point2D', x=0, y=0)
q = Point2D()
assert(hasattr(q, 'x'))
assert('x' not in q.__dict__)
q.x = 9
assert(hasattr(q, 'x'))
assert('x' in q.__dict__)
del q.x
assert(hasattr(q, 'x'))
assert('x' not in q.__dict__)
q['y'] = 6
assert(q['y'] == q.y)
assert(q['y'] is q.y)
del q['y']
assert(hasattr(q, 'y'))
assert('y' not in q.__dict__)
return True
def demo_duplication():
Unit = define('Unit', n=0)
u = Unit()
h = Unit(n=5)
assert(u is not h)
assert(u != h)
uc = u.copy()
assert(u is not uc)
assert(u == uc)
hc = h.copy()
assert(h is not hc)
assert(h == hc)
return True
if __name__ == "__main__":
tests = [test for test in dir(unit_tests) if 'demo_' in test]
total = len(tests)
tests_completed = 0
for test in tests:
tests_completed += eval('unit_tests.{name}()'.format(name=test))
print('{} tests completed of {} total.'.format(tests_completed, total))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment