`staticmethod` i` abc.abstractmethod`: czy to się połączy?

106

W mojej aplikacji w języku Python chcę utworzyć metodę, która będzie jednocześnie staticmethodrozszerzeniem a i abc.abstractmethod. Jak mam to zrobic?

Próbowałem zastosować oba dekoratory, ale to nie działa. Jeśli to zrobię:

import abc

class C(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    @staticmethod    
    def my_function(): pass

Dostaję wyjątek *, a jeśli to zrobię:

class C(object):
    __metaclass__ = abc.ABCMeta

    @staticmethod    
    @abc.abstractmethod
    def my_function(): pass

Metoda abstrakcyjna nie jest egzekwowana.

Jak mogę stworzyć abstrakcyjną metodę statyczną?

*Wyjątek:

File "c:\Python26\Lib\abc.py", line 29, in abstractmethod
 funcobj.__isabstractmethod__ = True
AttributeError: 'staticmethod' object has no attribute '__isabstractmethod__'
Ram Rachum
źródło
5
Zaktualizuj zaakceptowaną odpowiedź.
Neil G

Odpowiedzi:

34
class abstractstatic(staticmethod):
    __slots__ = ()
    def __init__(self, function):
        super(abstractstatic, self).__init__(function)
        function.__isabstractmethod__ = True
    __isabstractmethod__ = True

class A(object):
    __metaclass__ = abc.ABCMeta
    @abstractstatic
    def test():
        print 5
Rosz Oksymoron
źródło
7
Dobrze zagrane, proszę pana :-) Opuściłaś import abcna górze; a także podklasę, która pokazuje instancję A. (np. class B(A):\n @staticmethod\n def test():\n print 10\n)
Dan Breslau
1
Zaktualizowałem kod, aby działał poprawnie z podklasami. A. test również powinien mieć __isabstractmethod__atrybut.
Rosz Oksymoron
3
Należy abstractstaticdodać do abc.py?
nnyby
3
abstractstaticmethod Przestarzałe od wersji 3.3: jest teraz możliwe użycie staticmethod z abstractmethod (), dzięki czemu ten dekorator jest zbędny. link
irakli khitarishvili
1
@iraklikhitarishvili Jednak to nie wymusza statycznej metody podklasy! Musisz powielić dekorator metody statycznej ... Czy nie da się tego obejść?
étale-cohomology
199

Począwszy od Pythona 3.3 , jest możliwe łączenie @staticmethod i @abstractmethod, więc żadne inne sugestie są już konieczne:

@staticmethod
@abstractmethod
def my_abstract_staticmethod(...):
gerrit
źródło
32
Zauważ, że musisz ustawić @staticmethodjako pierwszy, albo dostanieszAttributeError: attribute '__isabstractmethod__' of 'staticmethod' objects is not writable
Marco Sulla
3
To samo dotyczy@property
zezollo
11
Byłoby naprawdę pomocne, gdyby taka była akceptowana odpowiedź!
Keerthana Prabhakaran
Dokładnie to, czego szukałem. Dzięki!
shanu khera
13

To zrobi to:

  >>> import abc
  >>> abstractstaticmethod = abc.abstractmethod
  >>>
  >>> class A(object):
  ...     __metaclass__ = abc.ABCMeta
  ...     @abstractstaticmethod
  ...     def themethod():
  ...          pass
  ... 
  >>> a = A()
  >>> Traceback (most recent call last):
  File "asm.py", line 16, in <module>
    a = A()
  TypeError: Can't instantiate abstract class A with abstract methods test

Mówisz „Eh? Po prostu zmienia nazwę @abstractmethod” i jest to całkowicie poprawne. Ponieważ każda podklasa powyższego i tak będzie musiała zawierać dekorator @staticmethod. Nie potrzebujesz tego tutaj, z wyjątkiem dokumentacji podczas czytania kodu. Podklasa musiałaby wyglądać tak:

  >>> class B(A):
  ...     @staticmethod
  ...     def themethod():
  ...         print "Do whatevs"

Aby mieć funkcję, która zmusiłaby cię do uczynienia tej metody metodą statyczną, musiałbyś podklasę ABCmeta, aby to sprawdzić i wymusić. To dużo pracy bez realnego zwrotu. (Jeśli ktoś zapomni dekoratora @staticmethod i tak otrzyma wyraźny błąd, po prostu nie wspomina o metodach statycznych.

W rzeczywistości działa to równie dobrze:

  >>> import abc
  >>>
  >>> class A(object):
  ...     __metaclass__ = abc.ABCMeta
  ...     @abc.abstractmethod
  ...     def themethod():
  ...         """Subclasses must implement this as a @staticmethod"""
  ...          pass

Aktualizacja - inny sposób, aby to wyjaśnić:

To, że metoda jest statyczna, kontroluje sposób jej wywoływania. Metoda abstrakcyjna nigdy nie jest wywoływana. Dlatego abstrakcyjna metoda statyczna jest pojęciem dość bezcelowym, z wyjątkiem celów dokumentacyjnych.

Lennart Regebro
źródło
4

Obecnie nie jest to możliwe w Pythonie 2.X, który wymusza tylko abstrakcyjną lub statyczną metodę, ale nie obie.

W Pythonie 3.2+ nowe dekoratory abc.abstractclassmethodi abc.abstractstaticmethodzostały dodane w celu połączenia ich egzekwowania bycia abstrakcyjnymi i statycznymi lub abstrakcyjnymi i metodą klas.

Zobacz wydanie Pythona 5867

Nacięcie
źródło
11
Chociaż nowe w Pythonie 3.2 abstractclassmethodi abstractstaticmethodzostały szybko wycofane w Pythonie 3.3, a także abstractproperty. docs.python.org/3/library/abc.html
glarrain
4
Do Twojej wiadomości: bugs.python.org/issue11610 opisuje deprywację i nowy sposób jej wykonania ...
FlipMcF