美文网首页
为什么在Python中不推荐使用staticmehtod

为什么在Python中不推荐使用staticmehtod

作者: 东方胖 | 来源:发表于2023-07-08 11:48 被阅读0次

    一、什么时候应该使用 staticmethod

    staticmethod 是一个装饰器,它的作用是改变函数方法的性质,让我们可以忽略掉第一个 self 参数,并且使得可以同时使用类名和对象去调用它。

    例如

    class Foo:
        def f(self, x):
            return x * 5
    

    f 的作用是将 x乘五倍。
    在流行的 IDE 如果我们写下以上的代码,可能会收到一个提示


    静态方法提示

    Method may be static
    哦,因为函数实现内部并没有特别的属于Foo 类对象的成员,所以IDE 提示我们应当把它改成静态方法,这表示表示方法不依赖这个类。

    可以改成这样:

    @staticmethod
        def f(x):
            return x * 5
    

    外部可以这样用

    Foo.f(10)
    
    # or
    foo = Foo()
    foo.f(10)
    

    如果跨越模块
    很可能就是长成这样的代码

    import foo # 假设模块名是 foo
    foo.Foo.f()
    

    下面我们要说——这样做不太好
    首先我们看到使用上有一点点别扭——foo.Foo.f() 这违背我们使用内置库函数的经验——例如使用 sin cos 函数,我们是这样的

    import math 
    math.sin(10)
    math.cos(1.0)
    

    或者

    from math import sin, cos
    sin(10)
    cos(1.0)
    

    单就这个case而言这不是一个好主意 ——代码不太简洁。我们可以把 staticmethod 改成模块函数

    什么时候应该用它?

    很少的场景必须要用staticmethod

    stackoverflow观点.png

    事实上,静态函数的概念来自 C++ 以及Java,至少我们可以这样类比。
    对于 Java 由于所有的代码 ,函数变量都放在一个 class 域内。
    我们总有一些方法是不需要通过生成对象再去调用,因为一方面生成对象总是要回收,总是要调用构造函数,带来了一些不必要的开销,因此总是得想办法设计出一些函数,直接通过类名去调用的。当然 Java 的对象同样可以调它类内定义的静态函数。
    而 C++ 略有区别,C++不允许通过对象的方式调用声明为static 的方法

    回到 Python,Python与C++的一大区别就是,它每个文件都在诞生的时候都自动成为一个 module,具有作用域的效力,与C++中 #include<filename.h> 再联动编译不同,所以,可以认为, Python的一个模块文件本身有 class的域作用。
    如果仅仅是为了封装的目的——即我们认为 f 函数是应该带个 Foo前缀,放在foo的范围内供其他工程师阅读,以示我们是明白 OO 编程,那么完全可以把这个方法写成模块级别的方法

    一篇更激进的文章

    这篇文章 原文链接 的观点更激进——他认为我们永远不要使用staticmethod

    概括一下他的理由

    • 找不到什么理由一定要用对象调用方法,比如 -5.abs() 而不是 Math.abs(-5)
    • Java把数学相关的方法放到 Math,但是他们的行为类比于Python 的classmathod。并举例 Jon Skeet (Google Senior Software Developer 《C# in Depth》的作者)认为 Java应该把静态方法设计成与 Python的类方法一样,并且不允许通过对象的方式调用
    • 当一组静态方法成群出现在一个类中是,类只是起到一个分组的作用,例如 Java的Math类收集一些数学相关的功能函数,但是 Python处理同样的问题是使用 module 模块。这就是我们开篇谈到的 point
    • 第四个理由作者说明,内建库中唯一使用 staticmetho的两个场景
      一个是
      str.maketrans()
      作者认为这个是可以用classmethod代替的。
      importlib.abc.InspectLoader.source_to_code()

    Python之父 Guido van Rossum 原话摘录 -basically said as much in April, 2012

    We all know how limited static methods are.(They’re basically an accident — back in the Python 2.2 days when I was inventing new-style classes and descriptors, I meant to implement class methods but at first I didn’t understand them and accidentally implemented static methods first. Then it was too late to remove them and only provide class methods.

    大概意思就是说,静态方法在 2.2 出现就是一个意外,后来意识到了它很废但是删除已经来不及

    代码规范

    大多数有气候的代码规范不推荐 或减少使用staticmethod
    例如谷歌开源项目代码规范
    谷歌开源项目代码规范Python——函数与方法装饰器

    这条tips:
    仅在有显著优势时, 审慎地使用装饰器. 避免使用 staticmethod. 减少使用 classmethod.**

    总结

    • 避免使用staticmethod。对于 Java转过来的 Python作者尤其注意,不要轻易在大脑中奖 staticmethod 等同于 Java 的static 方法
    • 最严肃的理由,是Python的语义特性,模块函数实际上有同等的功效。不应该再多此一举,破坏其简洁性
    • 对于习惯Java的程序员,在写Python的时候,尤其要注意,封装一切的习惯会导致你的代码非常啰嗦和繁琐,当程序出现 class1.obj1.obj2.method() 类似的代码时,通常一定是你搞错了什么,带来了糟糕的设计。

    参考链接

    https://www.webucator.com/article/when-to-use-static-methods-in-python-never/
    https://stackoverflow.com/questions/735975/static-methods-in-python
    https://docs.python.org/zh-cn/3/library/functions.html?highlight=staticmethod#staticmethod

    相关文章

      网友评论

          本文标题:为什么在Python中不推荐使用staticmehtod

          本文链接:https://www.haomeiwen.com/subject/dxtjudtx.html