【问题标题】:Can you use a static method as default parameter in __init__ in python classes?你可以在 python 类的 __init__ 中使用静态方法作为默认参数吗?
【发布时间】:2019-02-01 04:47:04
【问题描述】:

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

您当然可以只将静态方法设置为默认参数,但随后会出现其他问题。例如,如果我想访问函数名(我真正想要的),我不能立即使用__name__。我知道如何通过访问static_method.__func__.__name__ 以另一种方式做到这一点。但这似乎很笨拙,并且当您获得一个 staticmethod 对象时,似乎不打算以这种方式使用它。

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 能够工作,但那时该类似乎不存在。那么,最后一次,为什么?

【问题讨论】:

  • Python 中很少使用静态方法,因为它们可以而且应该是函数。将您的静态方法设为函数(在类之前定义或导入)也应该可以解决您的问题。
  • 静态方法并不少见......并且有很多适合它们的用例......我真的不明白它不是静态方法如何准确解决问题跨度>
  • @JoranBeasley 在多年的 Python 编码中,我了解了 2 个可能有用的案例,0 个应该完成的案例,以及一个原因为什么经常这样做。

标签: python oop static-methods


【解决方案1】:

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

第一个问题是,在运行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__ 的代码版本不同。

【讨论】:

    【解决方案2】:
    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__
    

    我猜??

    【讨论】:

    • 可行的想法,尽管@Blckknght 的回答解释了根本问题。 +1 虽然
    猜你喜欢
    • 1970-01-01
    • 2019-05-20
    • 2011-03-06
    • 2019-09-22
    • 2012-07-04
    • 1970-01-01
    • 1970-01-01
    • 2016-10-28
    相关资源
    最近更新 更多