| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
PR rebased to fix the enum doc fix from master. |
Sorry, something went wrong.
|
I rebased my PR and reverted the io and_pyio changes (they should be made in a separated PR). |
Sorry, something went wrong.
|
@serhiy-storchaka @gvanrossum @rhettinger: so, what do you think? this idea was rejected in 2015, but came back in 2021 and Guido likes the idea to make static methods callable. See also PR #25268 which makes staticmethod more "usable" to be used directly as a function. It's a tricky topic. We could also require to always use staticmethod when using directly a function as a method: class MyClass:
method = staticmethod(func)
But sometimes, we need functions which can be used directly as method without staticmethod(), to mimick built-in function. Well see https://bugs.python.org/issue43682 and https://bugs.python.org/issue20309 discussions ;-) |
Sorry, something went wrong.
|
I like the idea. Why was it rejected in 2015? |
Sorry, something went wrong.
|
staticmethod is a simple thing. It is only purpose to decorate functions before setting them as class attribute if we do not want to make them instance methods. There is no use cases for calling staticmethod object. Victor want to replace OpenWrapper with staticmethod(open) to keep builtin open a non-descriptor just for the case if some user code sets it as class attribute. This is very special case, and I think that it would be better to apply staticmethod immediately before setting a class attribute: class MyClass:
open = staticmethod(open)
In any case staticmethod is not perfect replacement of OpenWrapper. If we go this way, we should at least implement __doc__ for staticmethod, and preferably __repr__, __name__, __module__, __qualname__, __text_signature__, etc, etc. It is a big issue. |
Sorry, something went wrong.
I solved this in PR #25268, did you see my PR?
See also https://bugs.python.org/issue43682#msg389907:
It's a similar issue than PEP 570 (positional-only arguments) solved for Python re-implementation of a C extension. We should either prevent C extensions to behave than Python, or we should allow pure Python code to behave the same. Here the issue is complex (changing built-in functions or Python functions to add/remove descriptor), and I propose to only change staticmethod(). In the whole stdlib, I'm only aware of io.open which is used sometimes directly to define a method (without @staticmethod). But the issue happens with any built-in function whch is reimplemented in Python (e.g. in PyPy). |
Sorry, something went wrong.
|
I merged my PR #25268 and rebased this PR on top of it. By the way, just for consistency, should we also make class methods callable? I have no use case for that :-) |
Sorry, something went wrong.
|
By the way, just for consistency, should we also make class methods
callable? I have no use case for that :-)
I thought those are callable already.
|
Sorry, something went wrong.
|
Guido:
Me too, but hey, static methods and class methods are weird! $ python3 Python 3.9.2 (default, Feb 20 2021, 00:00:00) >>> def func(): pass ... >>> wrapper = classmethod(func) >>> wrapper() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'classmethod' object is not callable It's only callable when it goes throught the descriptor! |
Sorry, something went wrong.
|
Well, ignore my idea of making class methods callable. It makes no sense since it doesn't pass the class in this case. Example: def func(cls):
print(cls)
class MyClass:
method = classmethod(func)
MyClass.method()
MyClass().method()
MyClass.__dict__['method']()
The last call fails because it doesn't go trought the descriptor, and so the class method doesn't get the class argument. Output: vstinner@apu$ python3 x.py
<class '__main__.MyClass'>
<class '__main__.MyClass'>
Traceback (most recent call last):
File "/home/vstinner/python/master/x.py", line 9, in <module>
MyClass.__dict__['method']()
TypeError: 'classmethod' object is not callable
|
Sorry, something went wrong.
You should pass that in explicitly in that case. I guess calling classmethod(f)(C) could do the same thing as classmethod(f).__func__(C). But yeah, this doesn't seem as important as making staticmethod(f) callable, because there's nothing complicated there. |
Sorry, something went wrong.
There was a problem hiding this comment.
But please first fix the comment about class methods being callable.
Sorry, something went wrong.
There was a problem hiding this comment.
Class methods aren't callable yet.
Sorry, something went wrong.
Static methods (@staticmethod) are now callable as regular functions.
|
I fixed test_pydoc which shows a nice enhancement of this PR ;-) self.assertEqual(self._get_summary_lines(X.__dict__['sm']),
- 'sm(...)\n'
+ 'sm(x, y)\n'
' A static method\n')
With this PR, inspect.signature() works on a static method, and returns the same signature than the wrapped callable object. $ ./python Python 3.10.0a7+ >>> def func(x: int, y: int) -> float: pass ... >>> import inspect >>> inspect.signature(func) <Signature (x: int, y: int) -> float> >>> wrapper=staticmethod(func) >>> inspect.signature(wrapper) <Signature (x: int, y: int) -> float> On Python 3.9 (and in master without this change), inspect.signature(wrapper) fails with "TypeError: <staticmethod...> is not a callable object". |
Sorry, something went wrong.
|
Thanks for the review @gvanrossum. |
Sorry, something went wrong.
|
It is possible to wrap a static method into a new static method, staticmethod(staticmethod(func)) or put two @staticmethod decorators on the same function. It is inefficient, but I don't think that the staticmethod() constructor must return the first static method unchanged, since static methods are mutable. Python 3.10.0a7+ >>> def func(): return 5 ... >>> wrapper1 = staticmethod(func) >>> wrapper2 = staticmethod(wrapper1) >>> wrapper1 <staticmethod(<function func at 0x7fffea3071d0>)> >>> wrapper2 <staticmethod(<staticmethod(<function func at 0x7fffea3071d0>)>)> >>> wrapper2() 5 >>> wrapper2.x=1 >>> wrapper1.x Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'staticmethod' object has no attribute 'x' Moreover, I expect that most decorators have a similar issue. Maybe a linter or a debug check can warn on that, but I don't think that staticmethod() must raise an error or return the first (static method) wrapper unchanged. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Static methods created by the @staticmethod decorator are now
callable as regular functions.
https://bugs.python.org/issue43682