专栏首页志学Python将特性与Mixin类混合

将特性与Mixin类混合

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

本文分享自微信公众号 - 志学Python(lijinwen1996329ken),作者:志学Python

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一起来探讨 python 类爆炸问题

    由于您不必从特定的类派生对象就可以被程序重用,因此您可能会问为什么应该使用继承而不是仅实现所需的接口。以下规则可能对您有帮助

    公众号---志学Python
  • python算法队列

    3、练习:用上述的代码,完成67,45,34节点顺序放入队列,之后从队列的头部开始访问队列里的每一个元素。

    公众号---志学Python
  • 灵活的设计组合

    组合比继承更灵活,因为它可以建模松散耦合的关系。对组件类的更改对复合类影响很小或没有影响。基于组成的设计更适合更改

    公众号---志学Python
  • python笔记:线程

    2 锁 #创建锁 mutex = threading.Lock() #锁定 mutex.acquire([timeout]) #释放 mutex.release...

    超级大猪
  • PyQt5--GridLayout

    py3study
  • python 面向对象之添加功能

    ''' **#实现功能**案列 姓名:王飞 年龄:30 性别:男 工龄:5 我承诺,我会认真教课。 王飞爱玩象棋 姓名:小明 年龄:15 性别:男 学号:0...

    py3study
  • cxfreeze打包python程序的方法说明(生成安装包,实现桌面快捷方式、删除快捷方式)

    python代码文件转exe方法有三种,分别是cx_freeze,py2exe,PyInstaller,这三种方式各有千秋,本人只用过py2exe和cxfree...

    黯然销魂掌
  • 《Python基础教程》 读书笔记 第七章 更加抽象(上)

    面向对象程序设计中的术语对象(object)基本上可以看做数据(特性)以及由一系列可以存取、操作这些数据的方法所组成的集合。使用对象替代全局变量和函数的原因可能...

    统计学家
  • VR+全景播放器+头控讲解-07

    酷走天涯
  • python服务端多进程压测工具

    本文描述一个python实现的多进程压测工具,这个压测工具的特点如下: 多进程 在大多数情况下,压测一般适用于IO密集型场景(如访问接口并等待返回),在这种场景...

    用户1225216

扫码关注云+社区

领取腾讯云代金券