在Python中,底层是通过元类来创建对象的。这个元类有一个`__call__`方法,在创建类的实例时被触发。这个方法会调用你的类的`__new__`和`__init__`,然后最终将对象实例返回给调用者。请参考下面的图示以了解这个过程(图示参考
[1])。
![Instance creation in Python](https://istack.dev59.com/MCND4.webp)
说了这么多,我们只需在
__call__
中检查"required"属性即可。
元类
class ForceRequiredAttributeDefinitionMeta(type):
def __call__(cls, *args, **kwargs):
class_object = type.__call__(cls, *args, **kwargs)
class_object.check_required_attributes()
return class_object
我们在这里使用了
__call__
,我们创建了类对象,然后调用它的
check_required_attributes()
方法来检查是否定义了必需的属性。如果没有定义,我们就简单地抛出一个异常。
超类
class ForceRequiredAttributeDefinition(metaclass=ForceRequiredAttributeDefinitionMeta):
starting_day_of_week = None
def check_required_attributes(self):
if self.starting_day_of_week is None:
raise NotImplementedError('Subclass must define self.starting_day_of_week attribute. \n This attribute should define the first day of the week.')
三件事:
- 应该利用我们的元类。
- 应该将所需属性定义为
None
,参见starting_day_of_week = None
- 应该实现
check_required_attributes
方法,检查所需属性是否为None
,如果是,则抛出一个带有合理错误消息的NotImplementedError
给用户。
工作和不工作子类的示例
class ConcereteValidExample(ForceRequiredAttributeDefinition):
def __init__(self):
self.starting_day_of_week = "Monday"
class ConcereteInvalidExample(ForceRequiredAttributeDefinition):
def __init__(self):
pass
输出
Traceback (most recent call last):
File "test.py", line 50, in <module>
ConcereteInvalidExample()
File "test.py", line 18, in __call__
obj.check_required_attributes()
File "test.py", line 36, in check_required_attributes
raise NotImplementedError('Subclass must define self.starting_day_of_week attribute. \n This attribute should define the first day of the week.')
NotImplementedError: Subclass must define self.starting_day_of_week attribute.
This attribute should define the first day of the week.
第一个实例成功创建,因为它定义了所需的属性,而第二个实例引发了一个
NotImplementedError
错误。
def process_pages(list_of_pages): return [ page.page_name for page in list_of_pages ]
的意思是将给定页面列表中每个页面的名称提取出来并返回一个名称列表。 - chepner