fork(1) download
  1. from functools import partial, wraps
  2. from types import MethodType
  3.  
  4. class subscriptable:
  5. _SUBSCRIPT_KEY = '___SUBSCRIPT_KEY'
  6. _HAS_SUBSCRIPTABLE_METHODS = '___HAS_SUBSCRIPTABLE_METHODS'
  7.  
  8. def __init__(self, method):
  9. self._method = method
  10.  
  11. def _bind(self, instance):
  12. self._method = MethodType(self._method, instance)
  13.  
  14. def __getitem__(self, specified_type, *args, **kwargs):
  15. if not isinstance(specified_type, type):
  16. raise TypeError("Only Type Accessors are supported - must be an instance of `type`")
  17.  
  18. return partial(self.__call__, **{self.__class__._SUBSCRIPT_KEY: specified_type})
  19.  
  20. def __call__(self, *args, **kwargs):
  21. """A transparent passthrough to the wrapped method"""
  22. return self._method(*args, **kwargs)
  23.  
  24. def __str__(self):
  25. return f"<{self.__class__.__name__} {self._method}>"
  26.  
  27. @classmethod
  28. def has_key(cls, foo_kwargs):
  29. """A utility method to determine whether the provided kwargs has the expected subscript key"""
  30. return cls._SUBSCRIPT_KEY in foo_kwargs
  31.  
  32. @classmethod
  33. def key(cls, foo_kwargs:dict):
  34. """A utility method that allows the subscript key to be consumed by the wrapped method, without needing to know the inner workings"""
  35. return foo_kwargs.pop(cls._SUBSCRIPT_KEY, None)
  36.  
  37. @classmethod
  38. def container(cls, clazz):
  39. """A decorator for classes containing `subscriptable` methods"""
  40. if not hasattr(clazz, cls._HAS_SUBSCRIPTABLE_METHODS):
  41. orig_init = clazz.__init__
  42. @wraps(clazz.__init__)
  43. def __init__(self, *args, **kwargs):
  44. for attr_name in dir(self):
  45. attr_value = getattr(self, attr_name)
  46. if isinstance(attr_value, cls):
  47. attr_value._bind(self)
  48. orig_init(self, *args, **kwargs)
  49. clazz.__init__ = __init__
  50. setattr(clazz, cls._HAS_SUBSCRIPTABLE_METHODS, True)
  51. return clazz
  52.  
  53. @subscriptable.container
  54. class MyClass:
  55.  
  56. @subscriptable
  57. def compute_typed_value(self, value, *args, **kwargs):
  58. print(self, args, kwargs)
  59. if subscriptable.has_key(kwargs):
  60. value = subscriptable.key(kwargs)(value)
  61. self.my_other_method()
  62. return value
  63.  
  64. def my_other_method(self):
  65. print('Doing some other things!')
  66. return 3
  67.  
  68.  
  69. a = MyClass()
  70. b = MyClass()
  71. value = a.compute_typed_value[int]('12345')
Runtime error #stdin #stdout #stderr 0.14s 26392KB
stdin
Standard input is empty
stdout
<__main__.MyClass object at 0x14614b38dc70> ('12345',) {'___SUBSCRIPT_KEY': <class 'int'>}
stderr
Traceback (most recent call last):
  File "./prog.py", line 71, in <module>
  File "./prog.py", line 22, in __call__
  File "./prog.py", line 60, in compute_typed_value
TypeError: int() argument must be a string, a bytes-like object or a number, not 'MyClass'