能否在python类的__init__中使用静态方法作为默认参数?

时间:2019-02-01 04:47:04

标签: python oop static-methods

我正在为神经网络编写一个类,我想给它某种形式的自定义,以便您可以选择不同的成本函数和正则化。为此,我想在__init__()方法中将它们设置为默认参数。 但是当我在示例中通过MyClass.static_method时,解释器会告诉我MyClass尚未定义。为什么会这样,并且有比我更好的解决方法?

您当然可以只将static方法设置为默认参数,但是随后会出现其他问题。例如,如果我想访问函数名称(实际上是我想要的),则不能立即使用__name__。我知道如何通过访问static_method.__func__.__name__来完成此操作。但这似乎很笨拙,当您获得静态方法对象时,似乎不打算将其用于这种方式。

class MyClass:
    @staticmethod
    def static_method():
        do_something()

    def __init__(self, func=MyClass.static_method, func2=static_method):
        self.name = func.__name__                  #Does not work
        self.name2 = func2.__func__.__name__       #Should work

我确实希望MyClass.static_method能够正常工作,但是那时该类似乎并不存在。那么,最后一次,为什么?

2 个答案:

答案 0 :(得分:1)

DEFAULT = object()
class MyClass:
    @staticmethod
    def static_method():
        do_something()

    def __init__(self, func=DEFAULT, func2=DEFAULT):
        self.name = self.static_method.__name__  if func is DEFAULT else func.__name__
        self.name2 = self.static_method.__func__.__name__ if func2 is DEFAULT else func2.__func__.__name__

我猜??

答案 1 :(得分:0)

将静态方法用作默认参数时遇到问题的原因是两个问题的结合。

第一个问题是,运行def语句时,不仅要在调用函数时,还必须正确定义默认参数。这是因为默认参数内置在函数对象中,而不是每次函数运行时都要重新计算(这与可变的默认参数(如空列表)通常是错误的原因相同)。无论如何,这就是为什么您不能使用MyClass.static_method作为默认参数的原因,因为在定义函数时尚未定义MyClass(仅在所有类的内容都被创建之后才创建类对象)创建)。

下一个问题是staticmethod对象不具有与常规函数相同的属性和方法。通常,这并不重要,因为当您通过类对象(例如,MyClass.static_method存在后,例如MyClass或实例(例如,self.static_method)访问它时,它将可以调用并具有__name__。但这是因为在这种情况下,您可以获得基础功能,而不是staticmethod对象本身。 staticmethod对象本身是一个描述符,但不是可调用的。

因此这些功能均无法正常工作:

class MyClass:
    @staticmethod
    def static_method():
        pass

    def foo(self, func=MyClass.static_method): # won't work because MyClass doesn't exist yet
        pass

    def bar(self, func=static_method): # this declaration will work (if you comment out foo)
        name = func.__name__  # but this doesn't work when the bar() is called
        func()                # nor this, as func is the staticmethod object

有效的方法是使用staticmethod对象下面的实际函数作为默认函数:

    def baz(self, func=static_method.__func__):  # this works!
        name = func.__name__
        func()

当您传入其他函数(或绑定方法)时,这也适用,这与使用name = func.__func__.__name__的代码版本不同。