@@ -430,4 +430,112 @@ reveal_type(C.f2(1)) # revealed: str
430430reveal_type(C().f2(1 )) # revealed: str
431431```
432432
433+ ## ` @staticmethod `
434+
435+ ### Basic
436+
437+ When a ` @staticmethod ` attribute is accessed, it returns the underlying function object. This is
438+ true whether it's accessed on the class or on an instance of the class.
439+
440+ ``` py
441+ from __future__ import annotations
442+
443+ class C :
444+ @ staticmethod
445+ def f (x : int ) -> str :
446+ return " a"
447+
448+ reveal_type(C.f) # revealed: def f(x: int) -> str
449+ reveal_type(C().f) # revealed: def f(x: int) -> str
450+ ```
451+
452+ The method can then be called like a regular function from either the class or an instance, with no
453+ implicit first argument passed.
454+
455+ ``` py
456+ reveal_type(C.f(1 )) # revealed: str
457+ reveal_type(C().f(1 )) # revealed: str
458+ ```
459+
460+ When the static method is called incorrectly, we detect it:
461+
462+ ``` py
463+ C.f(" incorrect" ) # error: [invalid-argument-type]
464+ C.f() # error: [missing-argument]
465+ C.f(1 , 2 ) # error: [too-many-positional-arguments]
466+ ```
467+
468+ When a static method is accessed on a derived class, it behaves identically:
469+
470+ ``` py
471+ class Derived (C ):
472+ pass
473+
474+ reveal_type(Derived.f) # revealed: def f(x: int) -> str
475+ reveal_type(Derived().f) # revealed: def f(x: int) -> str
476+
477+ reveal_type(Derived.f(1 )) # revealed: str
478+ reveal_type(Derived().f(1 )) # revealed: str
479+ ```
480+
481+ ### Accessing the staticmethod as a static member
482+
483+ ``` py
484+ from inspect import getattr_static
485+
486+ class C :
487+ @ staticmethod
488+ def f (): ...
489+ ```
490+
491+ Accessing the staticmethod as a static member. This will reveal the raw function, as ` staticmethod `
492+ is transparent when accessed via ` getattr_static ` .
493+
494+ ``` py
495+ reveal_type(getattr_static(C, " f" )) # revealed: def f() -> Unknown
496+ ```
497+
498+ The ` __get__ ` of a ` staticmethod ` object simply returns the underlying function. It ignores both the
499+ instance and owner arguments.
500+
501+ ``` py
502+ reveal_type(getattr_static(C, " f" ).__get__ (None , C)) # revealed: def f() -> Unknown
503+ reveal_type(getattr_static(C, " f" ).__get__ (C(), C)) # revealed: def f() -> Unknown
504+ reveal_type(getattr_static(C, " f" ).__get__ (C())) # revealed: def f() -> Unknown
505+ reveal_type(getattr_static(C, " f" ).__get__ (" dummy" , C)) # revealed: def f() -> Unknown
506+ ```
507+
508+ ### Staticmethods mixed with other decorators
509+
510+ ``` toml
511+ [environment ]
512+ python-version = " 3.12"
513+ ```
514+
515+ When a ` @staticmethod ` is additionally decorated with another decorator, it is still treated as a
516+ static method:
517+
518+ ``` py
519+ from __future__ import annotations
520+
521+ def does_nothing[T](f: T) -> T:
522+ return f
523+
524+ class C :
525+ @ staticmethod
526+ @does_nothing
527+ def f1 (x : int ) -> str :
528+ return " a"
529+
530+ @does_nothing
531+ @ staticmethod
532+ def f2 (x : int ) -> str :
533+ return " a"
534+
535+ reveal_type(C.f1(1 )) # revealed: str
536+ reveal_type(C().f1(1 )) # revealed: str
537+ reveal_type(C.f2(1 )) # revealed: str
538+ reveal_type(C().f2(1 )) # revealed: str
539+ ```
540+
433541[ functions and methods ] : https://docs.python.org/3/howto/descriptor.html#functions-and-methods
0 commit comments