python中多重继承的用途之一是通过mixins扩展类功能。mixin是提供其他类方法的类,但不被视为基类
mixin允许其他类重用它的接口和实现,而不必成为超类。它们实现了一种独特的行为,这种行为可以聚合到其他不相关的类中。它们类似于构成,但它们创建了更强的关系
假设您希望将应用程序中某些类型的对象转换为对象的字典表示形式。您可以在希望支持此功能的每个类中提供.to_dict()方法,但是.to_dict()的实现似乎非常类似
这可能是混入的很好的候选人。首先,从构成示例中稍微修改Employee类
# In employees.py
class Employee:
def __init__(self, id, name, address, role, payroll):
self.id = id
self.name = name
self.address = address
self._role = role
self._payroll = payroll
def work(self, hours):
duties = self._role.perform_duties(hours)
print(f'Employee {self.id} - {self.name}:')
print(f'- {duties}')
print('')
self._payroll.track_work(hours)
def calculate_payroll(self):
return self._payroll.calculate_payroll()
变化很小。您只需在角色和工资单属性的名称上添加一个下划线,即可将其更改为内部属性。您很快就会知道为什么要进行更改
现在,您添加AsDictionaryMixin类
# In representations.py
class AsDictionaryMixin:
def to_dict(self):
return {
prop: self._represent(value)
for prop, value in self.__dict__.items()
if not self._is_internal(prop)
}
def _represent(self, value):
if isinstance(value, object):
if hasattr(value, 'to_dict'):
return value.to_dict()
else:
return str(value)
else:
return value
def _is_internal(self, prop):
return prop.startswith('_')
AsDictionaryMixin
类公开了一个.to_dict()
方法,该方法将自身的表示形式作为字典返回。这个方法是作为一个dict理解来实现的,它说,“如果这个道具不是内部的,那么为self.__dict__.items()
中的每一项创建一个映射道具到值的字典。”
正如您在开始时看到的,创建一个类从object继承了一些成员,其中一个成员是__dict__,它基本上是一个对象中所有属性到它们的值的映射
# In employees.py
from representations import AsDictionaryMixin
class Employee(AsDictionaryMixin):
def __init__(self, id, name, address, role, payroll):
self.id = id
self.name = name
self.address = address
self._role = role
self._payroll = payroll
def work(self, hours):
duties = self._role.perform_duties(hours)
print(f'Employee {self.id} - {self.name}:')
print(f'- {duties}')
print('')
self._payroll.track_work(hours)
def calculate_payroll(self):
return self._payroll.calculate_payroll()
您所要做的就是继承AsDictionaryMixin以支持该功能。最好在Address类中支持相同的功能,因此Employee.address属性以相同的方式表示
# In contacts.py
from representations import AsDictionaryMixin
class Address(AsDictionaryMixin):
def __init__(self, street, city, state, zipcode, street2=''):
self.street = street
self.street2 = street2
self.city = city
self.state = state
self.zipcode = zipcode
def __str__(self):
lines = [self.street]
if self.street2:
lines.append(self.street2)
lines.append(f'{self.city}, {self.state} {self.zipcode}')
return '\n'.join(lines)
您将mixin应用于Address类以支持该功能。现在,您可以编写一个小程序进行测试
# In program.py
import json
from employees import EmployeeDatabase
def print_dict(d):
print(json.dumps(d, indent=2))
for employee in EmployeeDatabase().employees:
print_dict(employee.to_dict())
该程序实现了print_dict()
,它使用缩进将字典转换为JSON字符串,因此输出看起来更好
然后,遍历所有员工,打印.to_dict()
提供的字典表示形式。您可以运行该程序以查看其输出
$ python program.py
{
"id": "1",
"name": "Mary Poppins",
"address": {
"street": "121 Admin Rd.",
"street2": "",
"city": "Concord",
"state": "NH",
"zipcode": "03301"
}
}
{
"id": "2",
"name": "John Smith",
"address": {
"street": "67 Paperwork Ave",
"street2": "",
"city": "Manchester",
"state": "NH",
"zipcode": "03101"
}
}
{
"id": "3",
"name": "Kevin Bacon",
"address": {
"street": "15 Rose St",
"street2": "Apt. B-1",
"city": "Concord",
"state": "NH",
"zipcode": "03301"
}
}
{
"id": "4",
"name": "Jane Doe",
"address": {
"street": "39 Sole St.",
"street2": "",
"city": "Concord",
"state": "NH",
"zipcode": "03301"
}
}
{
"id": "5",
"name": "Robin Williams",
"address": {
"street": "99 Mountain Rd.",
"street2": "",
"city": "Concord",
"state": "NH",
"zipcode": "03301"
}
}