tl; dr *Maybe* staticmethod could be modified to become callable?
io.open is a built-in function (type "builtin_function_or_method"). It behaves differently than _pyio.open which is a Python function (type "function"). The difference is in the LOAD_METHOD bytecode which uses __get__() descriptor if available. Built-in function has no __get__() method and so the function is used directly as a method. Python function has a __get__() descriptor which returns the function unchanged when a class method is requested, and create a bound method if an instance method is requested: --- def func(): ... FunctionType = type(func) class MyClass: method = func class_method = MyClass.method assert class_method is func assert class_method is FunctionType.__get__(func, None, MyClass) obj = MyClass() instance_method = obj.method assert instance_method.__self__ is obj assert instance_method.__func__ is func # each __get__() call creates a new bound method assert instance_method == FunctionType.__get__(func, obj, type(obj)) --- @staticmethod decorator avoids the creation of the bound method: --- def func(): ... class MyClass: method = staticmethod(func) # method = MyClass.method attr = MyClass.__dict__['method'] method = type(attr).__get__(attr, None, MyClass) assert method is func --- The drawback is that the object created by staticmethod cannot be called :-( The following code raises a TypeError: --- wrapped = staticmethod(func) wrapped() --- *Maybe* staticmethod could be modified to become callable? Victor On Wed, Mar 31, 2021 at 2:34 PM Victor Stinner <vstin...@python.org> wrote: > > Hi, > > The io module provides an open() function. It also provides an > OpenWrapper which only exists to be able to store open as a method > (class or instance method). In the _pyio module, pure Python > implementation of the io module, OpenWrapper is implemented as: > > class OpenWrapper: > """Wrapper for builtins.open > > Trick so that open won't become a bound method when stored > as a class variable (as dbm.dumb does). > > See initstdio() in Python/pylifecycle.c. > """ > def __new__(cls, *args, **kwargs): > return open(*args, **kwargs) > > I would like to remove this class which is causing troubles in the PEP > 597 implementation, but I don't know how. Simplified problem: > --- > def func(): > print("my func") > > class MyClass: > method = func > > func() # A > MyClass.method() # B > obj = MyClass() > obj.method() # C > --- > > With this syntax, A and B work, but C fails with TypeError: func() > takes 0 positional arguments but 1 was given. > > If I decorate func() with @staticmethod, B and C work, but A fails > with TypeError: 'staticmethod' object is not callable. > > Is OpenWrapper the only way to have a callable object which works in > the 3 variants A, B and C? > > A, B and C work if MyClass is modified to use staticmethod: > > class MyClass: > method = staticmethod(func) > > Victor > -- > Night gathers, and now my watch begins. It shall not end until my death. -- Night gathers, and now my watch begins. It shall not end until my death. _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/KAZ5HR2ZLPBZ76FZZOZI5RU35FYDBDI7/ Code of Conduct: http://python.org/psf/codeofconduct/