Last active
May 23, 2019 20:09
-
-
Save naufraghi/7df4cf49284b9ad605bdbdbc4dfc6afe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Checked(object): | |
""" | |
This class offers a `checked()` method that returns the same namedtuple after an user defined check. | |
The returned class is not exacly the same, but is in fact a copy with an added marker base class. | |
Given the `namedtuple` immutability, the marker base class is used to skip the checks after the first run. | |
""" | |
class Done: # Using `Done(object)` let the code work as expected in Python 2 too | |
__slots__ = () | |
__slots__ = () | |
def checked(self): | |
if isinstance(self, Checked.Done): | |
return self | |
self._check() | |
_Checked = type(self.__class__.__name__, self.__class__.__bases__ + (Checked.Done, ), | |
{"__slots__": ()}) | |
return _Checked(*self) | |
def _check(self): | |
"Override in subclasses" | |
pass | |
if __name__ == "__main__": | |
import sys | |
from collections import namedtuple | |
class Foo(namedtuple("Foo", "a b"), Checked): | |
__slots__ = () | |
def _check(self): | |
print("doing check for {name}".format(name=type(self).__name__)) | |
foo = Foo(1, 2) | |
fooc = foo.checked() | |
a = {} | |
print("pass 1") | |
# Sadly the instances are not preserved, even if the check passes | |
assert foo is not fooc | |
# The size of the object is preserved | |
try: | |
assert sys.getsizeof(foo) == sys.getsizeof(fooc) | |
except AssertionError: | |
print("Python 2 Warning: sizeof(foo)={0} != sizeof(fooc)={1}".format(sys.getsizeof(foo), sys.getsizeof(fooc))) | |
# Slots in type() declaration are not managed correctly in Python 2 | |
assert sys.version_info.major < 3 | |
# An the equality too | |
assert foo == fooc | |
a[foo] = True | |
print("pass 2") | |
# Should not print "doing check..." | |
assert foo == fooc.checked() | |
# Used as dictionary key, the checked and unckecked are equal | |
assert a[fooc] | |
# We can verify if an instance is checked or not | |
assert not isinstance(foo, Checked.Done) | |
assert isinstance(fooc, Checked.Done) | |
# Slots are preserved | |
try: | |
foo.bar = 12 | |
except AttributeError: | |
print("Unable to set foo.bar = 12") | |
else: | |
assert False | |
try: | |
fooc.bar = 12 | |
except AttributeError: | |
print("Unable to set fooc.bar = 12") | |
else: | |
print("Python 2 Warning: Able to set fooc.bar = 12") | |
# Slots in type() declaration are not managed correctly in Python 2 | |
assert sys.version_info.major < 3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Problem solved,
class Done:
should beclass Done(object):
to use the new style classes in Python 2 too.