使用self还是类名来调用静态方法

12

使用类名调用Python静态方法更为普遍,但对于较长的类名称可能会显得不太美观。有时候我会在同一类中使用self来调用静态方法,因为我发现这样看起来更清晰。

class ASomewhatLongButDescriptiveClassName:

   def __init__(self):
      # This works, but it's an eyesore
      ASomewhatLongButDescriptiveClassName.do_something_static()

      # This works too and looks cleaner.
      self.do_something_static()

   @staticmethod
   def do_something_static():
      print('Static method called.')

我的理解是,使用self调用静态方法会被解释为ClassName.static_method(self),其中self将被静态方法忽略。
(编辑:上述说法仅适用于实例方法,而非静态方法) 是否有任何具体原因我不应该在同一类中使用self来调用静态方法?

顺便说一句,这是一个姊妹问题,与Difference between calling method with self and with class name? 相关,该问题涉及非静态方法。


3
我理解使用self来调用静态方法与ClassName.static_method(self)相同[...],但实际上它们并不相同。这只适用于实例方法。虽然你在示例中正确地使用了它,所以我猜你只是误引用了其他链接的SO问题中的评论。 - Mike Scotty
3
如果您想在实例方法的上下文中使用静态方法(例如,在您的示例中的__init__),那么请务必使用self。当然,如果您想从实例外部访问该方法,则self将没有意义,因此您必须使用完整的类名。 - SimonR
3
让我们澄清一下“instance 外部”的含义。如果您创建了 foo = ASomewhatLongButDescriptiveClassName(),则应该通过 foo.do_something_static() 访问静态方法。请注意不要更改原意,并使翻译更加通俗易懂。 - tdelaney
1
我建议停止使用staticmethod,改用普通的模块级函数 - juanpa.arrivillaga
1
@DV82XL 更好的解决方案可能是根本不要将其作为方法,而只需将其作为常规函数放在类外部。 - juanpa.arrivillaga
显示剩余2条评论
2个回答

28

你说了几句话并不完全正确:

使用类名调用Python静态方法更为常见

这不是更常见,而是从类外部唯一的调用方式。例如:

class MyClass:
    @staticmethod
    def a_method():
        pass


MyClass.a_method()
在这个例子中,self.a_method() 是不起作用的,因为 self 指向的不是 MyClass 的一个实例。

使用 self 调用静态方法等同于调用 ClassName.static_method(self),而静态方法会忽略 self 参数。

但事实并非如此,例如:

class MyClass:
    @staticmethod
    def a_method():
        pass

    def another_method(self):
        # this is fine
        self.a_method()
        # this causes an error, as .a_method expects no arguments
        MyClass.a_method(self)

self指的是调用实例方法的类的实例(该方法有self参数,这个参数甚至不需要被称为self - 它只是第一个参数的名称,self是惯例)。

你可以在self上调用静态方法,因为self是具有静态方法的类的实例,因此具有该方法。您也可以直接在类上调用静态方法,因为静态方法不需要将对象实例作为第一个参数 - 这就是静态方法的目的。

在需要时使用self.a_method()即可,但请记住,self将引用作为对象实例化的类的对象,而不是您提到的特定类。

例如:

class ClassA:
    @staticmethod
    def a_method():
        print('a')

    def another_method(self):
        # prints whatever a_method for the class of self prints
        self.a_method()
        # always prints 'a', as a_method for ClassA prints 'a'
        ClassA.a_method()


class ClassB(ClassA):
    @staticmethod
    def a_method():
        print('b')


a = ClassA()
a.another_method()
b = ClassB()
b.another_method()

输出:

a
a
b
a

因此,你会发现从self.和从Class.调用是有区别的。


如果你想避免在调用中重复类名,another_method() 内部 ClassA.a_method() 调用的替代方法是 __class__.a_method()。这样做总是打印出 'a',因为 ClassAa_method 打印出 'a',而此处的 __class__ 就是 ClassA - undefined

-1
这里有两个使用静态函数的数字格式化示例: 首先是一个简单的千位分隔符格式化方法。
class Car:

    def __init__(self, color: str, mileage: int):
        self.color: str = color
        self.mileage: int = mileage

    @staticmethod
    def format_with_comma_separator(amount: float) -> str:
        return f"{amount:,}"

    def __str__(self):
        # notice that mileage is printed with commas for thousands separation
        return f'The {self.color} car has {Car.format_with_comma_separator(self.mileage)} miles.'


第二个示例将浮点数格式化为美国英语货币。
import locale

class Truck:

    def __init__(self, color: str, mileage: int, cost: float):
        self.color: str = color
        self.mileage: int = mileage
        self.cost: float = cost

    @staticmethod
    def format_currency(amount: float) -> str:
        # set locale to US
        locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
        # format currency value
        return locale.currency(amount, grouping=True)

    def __str__(self):
        # notice that mileage is printed with commas for thousands separation and cost is formatted as currency (US)
        return f'The {self.color} truck has {self.mileage:,} miles and costs {Truck.format_currency(self.cost)}.'


根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接