Một phụ lục để trả lời @nailxx 's:
Bạn có thể thiết lập __test__ = False
trong lớp cha mẹ và sau đó sử dụng một metaclass (xem This question với một số giải thích rực rỡ) để thiết lập nó lại là True khi subclassing.
(Cuối cùng, tôi tìm thấy một cái cớ để sử dụng một metaclass!)
Mặc dù __test__
là một thuộc tính gạch dưới đôi, chúng ta phải thiết lập một cách rõ ràng để True
, vì không phải cài đặt nó sẽ gây ra python chỉ để tra cứu thuộc tính tiếp tục lên trên MRO và đánh giá nó thành False
.
Do đó, chúng tôi cần kiểm tra tại buổi thuyết trình lớp cho dù một trong các lớp cha có __test__ = False
hay không. Nếu trường hợp này xảy ra và định nghĩa lớp hiện tại chưa tự đặt __test__
, chúng tôi sẽ thêm '__test__': True
vào dict thuộc tính.
Mã kết quả trông như thế này:
class TestWhenSubclassedMeta(type):
"""Metaclass that sets `__test__` back to `True` when subclassed.
Usage:
>>> class GenericTestCase(TestCase, metaclass=TestWhenSubclassed):
... __test__ = False
...
... def test_something(self):
... self.fail("This test is executed in a subclass, only.")
...
...
>>> class SpecificTestCase(GenericTestCase):
... pass
"""
def __new__(mcs, name, bases, attrs):
ATTR_NAME = '__test__'
VALUE_TO_RESET = False
RESET_VALUE = True
values = [getattr(base, ATTR_NAME) for base in bases
if hasattr(base, ATTR_NAME)]
# only reset if the first attribute is `VALUE_TO_RESET`
try:
first_value = values[0]
except IndexError:
pass
else:
if first_value == VALUE_TO_RESET and ATTR_NAME not in attrs:
attrs[ATTR_NAME] = RESET_VALUE
return super().__new__(mcs, name, bases, attrs)
Người ta có thể mở rộng này để một số hành vi tiềm ẩn hơn như “nếu tên bắt đầu bằng Abstract
, thiết __test__ = False
tự động”, nhưng tôi cho bản thân mình sẽ giữ sự phân công rõ ràng cho rõ ràng.
Hãy để tôi dán đơn giản để giải thích hành vi - và nhắc nhở mọi người nên dành hai phút để kiểm tra mã của họ sau khi giới thiệu một tính năng.
from unittest import TestCase
from .base import TestWhenSubclassedMeta
class SubclassesTestCase(TestCase):
def test_subclass_resetted(self):
class Base(metaclass=TestWhenSubclassedMeta):
__test__ = False
class C(Base):
pass
self.assertTrue(C.__test__)
self.assertIn('__test__', C.__dict__)
def test_subclass_not_resetted(self):
class Base(metaclass=TestWhenSubclassedMeta):
__test__ = True
class C(Base):
pass
self.assertTrue(C.__test__)
self.assertNotIn('__test__', C.__dict__)
def test_subclass_attr_not_set(self):
class Base(metaclass=TestWhenSubclassedMeta):
pass
class C(Base):
pass
with self.assertRaises(AttributeError):
getattr(C, '__test__')
Lệnh '__test__ = false' Bí quyết là không phải là rất hữu ích trong trường hợp của một lớp cha mẹ, điều này sẽ buộc trẻ em lớp để xác định một cách rõ ràng '__test__ = TRUE' hoặc nó sẽ bị bỏ qua, đó là một nguy hiểm lừa để sử dụng. – Guibod