Вызов класса staticmethod в теле класса?



когда я пытаюсь использовать статический метод в теле класса, и определить статический метод с помощью встроенного staticmethod функция в качестве декоратора, как это:



class Klass(object):

@staticmethod # use as decorator
def _stat_func():
return 42

_ANS = _stat_func() # call the staticmethod

def method(self):
ret = Klass._stat_func() + Klass._ANS
return ret


я получаю следующее сообщение об ошибке:



Traceback (most recent call last):<br>
File "call_staticmethod.py", line 1, in <module>
class Klass(object):
File "call_staticmethod.py", line 7, in Klass
_ANS = _stat_func()
TypeError: 'staticmethod' object is not callable


Я понимаю, почему это происходит (дескриптор привязки), и может работать вокруг него путем ручного преобразования _stat_func() в staticmethod после его последнего использования, например, так:



class Klass(object):

def _stat_func():
return 42

_ANS = _stat_func() # use the non-staticmethod version

_stat_func = staticmethod(_stat_func) # convert function to a static method

def method(self):
ret = Klass._stat_func() + Klass._ANS
return ret


так что мой вопрос это:



там лучше, как чище и более "подходящие для Python", способов сделать это?

528   6  

6 ответов:

staticmethod объекты, по-видимому, имеют __func__ атрибут, хранящий исходную необработанную функцию (имеет смысл, что они должны были). Так что это будет работать:

class Klass(object):

    @staticmethod  # use as decorator
    def stat_func():
        return 42

    _ANS = stat_func.__func__()  # call the staticmethod

    def method(self):
        ret = Klass.stat_func()
        return ret

в стороне, хотя я подозревал, что объект staticmethod имеет какой-то атрибут, хранящий исходную функцию, я понятия не имел о специфике. В духе обучения кого-то ловить рыбу, а не давать им рыбу, это то, что я сделал, чтобы исследовать и выяснить это (буквально C&P от моего Python сессия):

>>> class Foo(object):
    @staticmethod
    def foo():
        return 3
    global z
    z = foo

>>> z
<staticmethod object at 0x0000000002E40558>
>>> Foo.foo
<function foo at 0x0000000002E3CBA8>
>>> dir(z)
['__class__', '__delattr__', '__doc__', '__format__', '__func__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>> z.__func__
<function foo at 0x0000000002E3CBA8>

подобные виды копания в интерактивном сеансе (dir очень полезно) часто может решить такие вопросы очень быстро.

вот как я предпочитаю:

class Klass(object):

    @staticmethod
    def stat_func():
        return 42

    _ANS = stat_func.__func__()

    def method(self):
        return self.__class__.stat_func() + self.__class__._ANS

Я предпочитаю это решение Klass.stat_func из-за сухой принцип. Напоминает мне о причина, почему есть новый super() в Python 3 :)

но я согласен с другими, обычно лучшим выбором является определение функции уровня модуля.

например,@staticmethod функция, рекурсия может выглядеть не очень хорошо (вам нужно будет сломать сухой принцип, вызвав Klass.stat_func внутри Klass.stat_func). Это потому что у вас нет ссылки на self внутри статического метода. С функцией уровня модуля все будет выглядеть нормально.

Это связано с тем, что staticmethod является дескриптором и требует выборки атрибута уровня класса для выполнения протокола дескриптора и получения истинного вызываемого объекта.

в исходном коде:

Он может быть вызван либо на класс (например C.f()) или на экземпляре (например,C().f()); экземпляр игнорируется, за исключением его класса.

но не непосредственно из класса, пока он определяется.

но как один комментатор упомянутый, это на самом деле не "Питонический" дизайн вообще. Просто используйте функцию модуля.

Как насчет этого решения? Он не полагается на знание @staticmethod реализация декоратора. Внутренний класс StaticMethod играет как контейнер статических функций инициализации.

class Klass(object):

    class StaticMethod:
        @staticmethod  # use as decorator
        def _stat_func():
            return 42

    _ANS = StaticMethod._stat_func()  # call the staticmethod

    def method(self):
        ret = self.StaticMethod._stat_func() + Klass._ANS
        return ret

Как насчет введения атрибута класса после определения класса?

class Klass(object):

    @staticmethod  # use as decorator
    def stat_func():
        return 42

    def method(self):
        ret = Klass.stat_func()
        return ret

Klass._ANS = Klass.stat_func()  # inject the class attribute with static method value

согласно блогу ниже, при вызове статического метода в классе вызывающая функция должна быть методом класса, поэтому добавление @classmethod к вашему определению метода может решить проблему.

окончательное руководство по использованию статических, классовых или абстрактных методов в Python

Comments

    Ничего не найдено.