メタクラスとしてabc.ABCMeta
を持ち、Python 2.7およびPython 3.5。 2.7または3.5でのみこれを行うことに成功しましたが、両方のバージョンで同時に実行することはありませんでした。
Python 2.7:
import abc
class SomeAbstractClass(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def do_something(self):
pass
Python 3.5:
import abc
class SomeAbstractClass(metaclass=abc.ABCMeta):
@abc.abstractmethod
def do_something(self):
pass
適切なバージョンのPythonインタープリター(Python 2.7->例1 Python 3.5->例2))を使用して次のテストを実行すると、成功します両方のシナリオで:
import unittest
class SomeAbstractClassTestCase(unittest.TestCase):
def test_do_something_raises_exception(self):
with self.assertRaises(TypeError) as error:
processor = SomeAbstractClass()
msg = str(error.exception)
expected_msg = "Can't instantiate abstract class SomeAbstractClass with abstract methods do_something"
self.assertEqual(msg, expected_msg)
Python 3.5を使用してテストを実行している間、期待される動作は発生しません(TypeError
のインスタンス化中にSomeAbstractClass
は発生しません):
======================================================================
FAIL: test_do_something_raises_exception (__main__.SomeAbstractClassTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/tati/sample_abc.py", line 22, in test_do_something_raises_exception
processor = SomeAbstractClass()
AssertionError: TypeError not raised
----------------------------------------------------------------------
一方、Python 2.7を使用してテストを実行すると、SyntaxError
が発生します。
Python 2.7 incompatible
Raises exception:
File "/home/tati/sample_abc.py", line 24
class SomeAbstractClass(metaclass=abc.ABCMeta):
^
SyntaxError: invalid syntax
six.add_metaclass
または six.with_metaclass
を使用できます。
import abc, six
@six.add_metaclass(abc.ABCMeta)
class SomeAbstractClass():
@abc.abstractmethod
def do_something(self):
pass
six
は Python 2および3互換性ライブラリ です。 pip install six
を実行するか、six.py
の最新バージョンをプロジェクトディレクトリにダウンロードしてインストールできます。
future
よりもsix
を好む人にとって、関連する関数は future.utils.with_metaclass
です。
Aaron Hallの答え が好きですが、この場合、行の一部であるコメントに注意することが重要です:
ABC = abc.ABCMeta('ABC', (object,), {}) # compatible with Python 2 *and* 3
...コード自体と同じくらい重要です。コメントがなければ、将来のカウボーイが行を削除してクラスの継承を次のように変更するのを防ぐことはできません:
class SomeAbstractClass(abc.ABC):
...したがって、pre Python 3.4。
あなたが達成しようとしていることに関して、それは自己文書化であるという点で、他の誰かにもう少し明示的/明確であるかもしれない1つの微調整:
import sys
import abc
if sys.version_info >= (3, 4):
ABC = abc.ABC
else:
ABC = abc.ABCMeta('ABC', (), {})
class SomeAbstractClass(ABC):
@abc.abstractmethod
def do_something(self):
pass
厳密に言えば、これは実行する必要はありませんが、コメントがなくても何が起こっているかは明確です。
_abc.ABCMeta
_を使用する場合、Python 2)で明示的にstr('ABC')
を_from __future__ import unicode_literals
_に渡す必要があると言うだけです。
それ以外の場合PythonはTypeError: type() argument 1 must be string, not unicode
を発生させます。
以下の修正されたコードを参照してください。
_import sys
import abc
from __future__ import unicode_literals
if sys.version_info >= (3, 4):
ABC = abc.ABC
else:
ABC = abc.ABCMeta(str('ABC'), (), {})
_
これには個別の回答は必要ありませんが、残念ながら私はあなたのものにコメントすることはできません(さらに担当者が必要です)。