Можете ли вы использовать статический метод в качестве параметра по умолчанию в __init__ в классах Python? - PullRequest
0 голосов
/ 01 февраля 2019

Я пишу класс для нейронной сети, и я хочу дать ему некоторую форму настройки, чтобы вы могли выбирать различные функции стоимости и регуляризации.Для этого я хочу установить их как параметры по умолчанию в методе __init__().Но когда я передаю MyClass.static_method в моем примере, интерпретатор сообщает мне, что MyClass (еще) не определен.Почему это так и есть ли лучший обходной путь, чем мой?

Конечно, вы можете просто установить статический метод в качестве параметра по умолчанию, но тогда возникают другие проблемы.Например, если я хочу получить доступ к имени функции (которое я на самом деле хочу), я не могу использовать __name__ righttaway.Я знаю, как сделать это по-другому, получив доступ к 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 сработает, но класс, похоже, не работаетсуществовать тогда.Итак, в последний раз, почему?

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Причиной возникновения проблем с использованием статического метода в качестве аргумента по умолчанию является комбинация двух проблем.

Первая проблема заключается в том, что аргумент по умолчанию должен быть четко определен, когда *Оператор 1003 * выполняется не только при вызове функции.Это потому, что аргумент по умолчанию встроен в объект функции, а не пересчитывается при каждом запуске функции (это та же самая причина, по которой изменяемый аргумент по умолчанию, такой как пустой список, часто является ошибкой).В любом случае, именно поэтому вы не можете использовать 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__.

0 голосов
/ 01 февраля 2019
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__

Полагаю, ??

...