`staticmethod` và` abc.abstractmethod`: Nó sẽ hòa trộn?


106

Trong ứng dụng Python của mình, tôi muốn tạo một phương thức vừa là a staticmethodvừa là abc.abstractmethod. Làm thế nào để tôi làm điều này?

Tôi đã thử áp dụng cả hai trình trang trí, nhưng nó không hoạt động. Nếu tôi làm điều này:

import abc

class C(object):
    __metaclass__ = abc.ABCMeta

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

Tôi nhận được một ngoại lệ * và nếu tôi làm điều này:

class C(object):
    __metaclass__ = abc.ABCMeta

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

Phương thức trừu tượng không được thực thi.

Làm cách nào để tạo một phương thức tĩnh trừu tượng?

*Sự ngoại lệ:

File "c:\Python26\Lib\abc.py", line 29, in abstractmethod
 funcobj.__isabstractmethod__ = True
AttributeError: 'staticmethod' object has no attribute '__isabstractmethod__'

5
Vui lòng cập nhật câu trả lời được chấp nhận của bạn.
Neil G

Câu trả lời:


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

7
Chơi tốt, thưa ông hoặc bà :-) Bạn đã bỏ ra import abcở trên cùng; cũng như một lớp con rằng chương trình õ của A. (ví dụ class B(A):\n @staticmethod\n def test():\n print 10\n)
Dan Breslau

1
Tôi đã cập nhật mã để hoạt động bình thường với phân lớp. A.test cũng nên có __isabstractmethod__thuộc tính.
Rosh Oxymoron

3
Nên abstractstaticthêm ngược dòng vào abc.py?
nnyby

3
trừu tượng hóa liên kết
irakli khitarishvili

1
@iraklikhitarishvili Tuy nhiên, điều đó không bắt buộc phương thức của lớp con là tĩnh! Bạn phải sao chép trình trang trí staticmethod ... Không có cách nào xung quanh điều đó?
étale-cohomology

199

Bắt đầu với Python 3.3 , có thể kết hợp @staticmethod@abstractmethodvì vậy không có đề xuất nào khác là cần thiết nữa:

@staticmethod
@abstractmethod
def my_abstract_staticmethod(...):

32
Lưu ý rằng bạn phải đặt @staticmethodnhư trước, nếu không bạn sẽ nhận đượcAttributeError: attribute '__isabstractmethod__' of 'staticmethod' objects is not writable
Marco Sulla

3
Tương tự cho@property
zezollo

11
Sẽ thực sự hữu ích nếu đây là câu trả lời được chấp nhận!
Keerthana Prabhakaran

Chính xác những gì tôi đang tìm kiếm. Cảm ơn!
shanu khera

13

Điều này sẽ làm điều đó:

  >>> 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

Bạn đi "Hả? Nó chỉ đổi tên @abstractmethod", và điều này hoàn toàn chính xác. Bởi vì bất kỳ lớp con nào ở trên sẽ phải bao gồm trình trang trí @staticmethod. Bạn không cần nó ở đây, ngoại trừ làm tài liệu khi đọc mã. Một lớp con sẽ phải trông như thế này:

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

Để có một hàm bắt buộc bạn đặt phương thức này thành một phương thức tĩnh, bạn sẽ phải phân lớp ABCmeta để kiểm tra điều đó và thực thi nó. Đó là rất nhiều công việc không có lợi nhuận thực sự. (Nếu ai đó quên bộ trang trí @staticmethod, họ sẽ nhận được lỗi rõ ràng, nó sẽ không đề cập đến các phương thức tĩnh.

Vì vậy, trên thực tế, điều này cũng hoạt động:

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

Cập nhật - Một cách khác để giải thích nó:

Đó là một phương thức tĩnh điều khiển cách nó được gọi. Một phương thức trừu tượng không bao giờ được gọi. Và phương thức tĩnh trừu tượng do đó là một khái niệm khá vô nghĩa, ngoại trừ mục đích tài liệu.


4

Điều này hiện không thể thực hiện được trong Python 2.X, điều này sẽ chỉ thực thi phương thức là trừu tượng hoặc tĩnh, chứ không phải cả hai.

Trong Python 3.2+, các trình trang trí mới abc.abstractclassmethodabc.abstractstaticmethod được thêm vào để kết hợp việc thực thi trừu tượng và tĩnh hoặc trừu tượng và một phương thức lớp.

Xem Sự cố Python 5867


11
Mặc dù mới trong Python 3.2, abstractclassmethodabstractstaticmethodnhanh chóng bị phản đối trong Python 3.3, cũng như abstractproperty. docs.python.org/3/library/abc.html
glarrain

4
FYI: bug.python.org/issue11610 mô tả mô tả và cách mới để thực hiện ...
FlipMcF
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.