Question: I'm attempting to add an item getter (__getitem__, to provide the [] syntax) to a class method so that I can use some unique-ish syntax to provide types to functions outside the normal parentheses, like the following. The syntax on the last line (of this first snippet) is really the goal for this whole endeavor. class MyClass: @typedmethod def compute_typed_value(self, value, *args, **kwargs): print(self, args, kwargs) result = TypedMethod.requested_type(kwargs)(value) self.my_other_method() return result def my_other_method(self): print('Doing some other things!') return 3 a = MyClass() a.compute_typed_value[int]('12345') # returns int value 12345  Additionally, I'd like to retain the intuitive behavior that a defined function can be called like a function, potentially with a default value for the type, like so: a = MyClass() a.compute_typed_value('12345') # should return whatever the default type is, with the value of '12345', # or allow some other default behavior  In a broader context, this would be implemented as a piece of an API adapter that implements a generic request processor, and I'd like the data to come out of the API adapter in a specific format. So the way that this might look in actual use could be something like the following:  @dataclass class MyAPIData: property_a: int = 0 property_b: int = 0 class MyAPIAdapter: _session def __init__(self, token): self._init_session(token) @typedmethod def request_json(self, url, **kwargs): datatype = TypedMethod.requested_type(kwargs) response_data = self._session.get(url).json() if datatype: response_data = datatype(**response_data) return response_data def fetch_myapidata(self, search): return self.request_json[MyAPIData](f"/myapi?q={search}")  I'm attempting to achieve this kind of behavior with a decorator that I can throw onto any function that I want to enable this behavior. Here is my current full implementation:  from functools import partial class TypedMethod: _REQUESTED_TYPE_ATTR = '__requested_type' def __init__(self, method): self._method = method print(method) self.__call__ = method.__call__ def __getitem__(self, specified_type, *args, **kwargs): print(f'getting typed value: {specified_type}') if not isinstance(specified_type, type): raise TypeError("Only Type Accessors are supported - must be an instance of `type`") return partial(self.__call__, **{self.__class__._REQUESTED_TYPE_ATTR: specified_type}) def __call__(self, *args, **kwargs): print(args, kwargs) return self._method(self, *args, **kwargs) @classmethod def requested_type(cls, foo_kwargs): return foo_kwargs[cls._REQUESTED_TYPE_ATTR] if cls._REQUESTED_TYPE_ATTR in foo_kwargs else None def typedmethod(foo): print(f'wrapping {foo.__name__} with a Typed Method: {foo}') _typed_method = TypedMethod(foo) def wrapper(self, *args, **kwargs): print('WRAPPER', self, args, kwargs) return _typed_method(self, *args, **kwargs) _typed_method.__call__ = wrapper return _typed_method class MyClass: @typedmethod def compute_typed_value(self, value, *args, **kwargs): print(self, args, kwargs) result = TypedMethod.requested_type(kwargs)(value) print(result) self.my_other_method() return result def my_other_method(self): print('Doing some other things!') return 3 a = MyClass() a.compute_typed_value[int]('12345')  If you run this code, it will fail stating that 'TypedMethod' object has no attribute 'my_other_method'. Further inspection reveals that the first line of compute_typed_value is not printing what one would intuitively expect from the code:  <__main__.TypedMethod object at 0x10754e790> () {'__requested_type': <class 'int'>}  Specifically, the first item printed, which is a TypedMethod instead of a MyClass instance Basically, the idea is use the __getitem__ callout to generate a functools.partial so that the subsequent call to the resulting function contains the __getitem__ key in a known "magic" kwargs value, which should hypothetically work, except that now the self reference that is available to MyClass.compute_typed_value is actually a reference to the TypedMethod instance generated by the wrapper instead of the expected MyClass instance. I've attempted a number of things to get the MyClass instance passed as self, but since it's implemented as a decorator, the instance isn't available at the time of decoration, meaning that somehow it needs to be a bound method at the time of function execution, I think.  I know I could just pass this value in as like the first positional argument, but I want it to work with the square bracket annotation because I think it'd be cool and more readable. This is mostly a learning exercise to understand more of Python's inner workings, so the answer could ultimately be "no".

Answer: I never thought I would use a Python class this way, but if the pattern fits... I put a cleaned-up example of the below answer in this github gist that shows the same implementation and usage.  The issue I was having was that the class instance reference (self) was being overridden due to the reassignment of the function itself via a decorator. My solution is basically to add another class-level decorator to manually put that reference back. This looks a little different than my originally asked question due to a change in naming, but the essence is still the same. We define a class that is itself used as the decorator. Python just allows this because class types, when called, are function calls themselves, to create and init a new instance of the class. This also allows us to provide a few more magic methods to make other quality of life items easier. Here's what that looks like: from functools import partial, wraps from types import MethodType from functools import partial, wraps from types import MethodType, FunctionType from typing import Any, Callable class subscriptable: _SUBSCRIPT_KEY = '___SUBSCRIPT_KEY' _HAS_SUBSCRIPTABLE_METHODS = '___HAS_SUBSCRIPTABLE_METHODS' _callout: Callable def __init__(self, callout: Callable, instance: Any = None): if instance is not None and isinstance(callout, FunctionType): self._callout = MethodType(callout, instance) else: self._callout = callout def bind(self, instance): return self.__class__(self._callout, instance=instance) def __getitem__(self, specified_type): return partial(self.__call__, **{self.__class__._SUBSCRIPT_KEY: specified_type}) def __call__(self, *args, **kwargs): """A transparent passthrough to the wrapped method""" return self._callout(*args, **kwargs) def __str__(self): return f"<{self.__class__.__name__} {self._callout}>" @classmethod def has_key(cls, foo_kwargs): """A utility method to determine whether the provided kwargs has the expected subscript key""" return cls._SUBSCRIPT_KEY in foo_kwargs @classmethod def key(cls, foo_kwargs:dict): """A utility method that allows the subscript key to be consumed by the wrapped method, without needing to know the inner workings""" return foo_kwargs.pop(cls._SUBSCRIPT_KEY, None) @classmethod def container(cls, clazz): """A decorator for classes containing `subscriptable` methods""" if not hasattr(clazz, cls._HAS_SUBSCRIPTABLE_METHODS): orig_init = clazz.__init__ @wraps(clazz.__init__) def __init__(self, *args, **kwargs): for attr_name in dir(self): attr_value = getattr(self, attr_name) if isinstance(attr_value, cls): setattr(self, attr_name, attr_value.bind(self)) orig_init(self, *args, **kwargs) clazz.__init__ = __init__ setattr(clazz, cls._HAS_SUBSCRIPTABLE_METHODS, True) return clazz   As a bonus feature, As some previously written answers allude to, class functions are not the only place that something like this might be useful, so this also allows for standalone functions to exhibit the same behavior. See this example, and its output:  @subscriptable def other_typed_value(value, **kwargs): subscript = subscriptable.key(kwargs) print(subscript, value) value = other_typed_value[int]('12345') value = other_typed_value('12345') print("Standard function str:", other_typed_value)  Produces the output: <class 'int'> 12345 None 12345 Standard function str: <subscriptable <function other_typed_value at 0x000001DC809384C0>>   And finally, the original point of the question, whether we can apply this pattern to class methods. The answer is yes, but with the assistance of yet another decorator. This is where subscriptable.container steps in. Since we can't access the instance at the time of class definition, I used an additional decorator to provide a pre-init hook that initializes all the functions so they are usable as expected (as properly bound class methods, even!), available even in the __init__ function. This kind of processing is probably pretty slow, but for my use case, it's mostly for singletons anyway. @subscriptable.container class MyClass: @subscriptable def compute_typed_value(self, value, *args, **kwargs): print(self, args, kwargs) if subscriptable.has_key(kwargs): value = subscriptable.key(kwargs)(value) self.my_other_method() return value def my_other_method(self): print('Doing some other things!') return 3 a = MyClass() value = a.compute_typed_value[int]('12345') print(value, type(value)) value = a.compute_typed_value('12345') print(value, type(value)) print("Class Method str:", a.compute_typed_value)  Anyhoo, the above code yields the following output, which you'll notice has all the correct references in the places they were missing before. great success! Doing some other things! 12345 <class 'int'> <__main__.MyClass object at 0x000001DC808EB1C0> () {} Doing some other things! 12345 <class 'str'> Class Method str: <subscriptable <bound method MyClass.compute_typed_value of <__main__.MyClass object at 0x000001DC808EB1C0>>>  I was hoping to do this without a second decorator, but a single class decorator to enable the desired behavior when I'm already using one is a price I'm willing to pay.