• 0
  • 0
分享
  • 测试开发之Python核心笔记(22):组合、继承与多态
  • 饭团🍙 2020-11-25 10:48:28 字数 6552 阅读 2398 收藏 0

       1、多用组合

       不同的类可以混合使用,加入到其他类中,来增强类的功能和代码重用性。也就是一个类的属性可以是其他类的实例。当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好。

       来看一个例子:

class Name:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
    def __str__(self):
        return "{}.{}".format(self.first_name, self.last_name)
class Address:
    def __init__(self, province, city):
        self.province = province
        self.city = city
    def __str__(self):
        return "{}-{}".format(self.province, self.city)
class Person:
    def __init__(self, name, address):
        self.name = name
        self.address = address
    def __str__(self):
        return "姓名:{},地址:{}".format(self.name, self.address)
if __name__ == '__main__':
    p = Person(Name("Chunming", "liu"), Address("beijing", "beijing"))
    print(p)

       我们知道圆环是由两个圆组成的。圆环的面积是外圆的面积减去内圆的面积,圆环的周长是外圆周长加上内圆的周长。用类的组成思路,定义圆环,在圆环类中组合圆形的实例作为自己的属性:

from math import pi
class Circle:
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return pi * self.radius * self.radius
    def perimeter(self):
        return 2 * pi * self.radius
class Ring:
    def __init__(self, inner_radius, outer_radius):
        self.inner_radius = Circle(inner_radius)  # 组合圆形类作为自己的属性
        self.outer_radius = Circle(outer_radius)
    def area(self):
        return self.outer_radius.area() - self.inner_radius.area()   # 重用圆形类的方法
    def perimeter(self):
        return self.inner_radius.perimeter() + self.outer_radius.perimeter()
if __name__ == '__main__':
    r = Ring(10, 20)
    print(r.area())
    print(r.perimeter())

       2、少用继承

  • 继承,指的是子类既拥有父类的特征(类的属性和函数)。

  • 子类也拥有不同于父类的独特特征(自定义的属性和函数)。

  • Python支持多继承,但是尽量别这么做。

  • 子类可以覆盖父类的同名方法

  • 所有的类默认情况下都是继承自object类

  • 用issubclass() 检查类继承关系

  • 通过__bases__属性可以类的所有父类

       2.1单继承

       看例子,学继承

class Entity(object):  # 父类
    def __init__(self, object_type, title):
        print('parent class init called')
        self.object_type = object_type
        self.title = title
    def get_context_length(self):
        return None
    def __repr__(self):
        return self.title + "." + self.object_type
class Document(Entity):  # 1.括号中写父类,可以写多个,表示继承多个类
    def __init__(self, object_type, title, author, context):
        print('Document class init called')
        super(Document, self).__init__(object_type, title)  # 2.自定义了__init__,则必须显示调用父类构造方法
        self.author = author  # 3.新增自己的属性
        self.__context = context
    def get_context_length(self):  # 4.覆盖父类的方法
        return len(self.__context)
class Video(Entity):
    pass  # 没有复写__init__方法,则会自动调用父类的__init__方法完成初始化。
class Music(Entity):
    def __init__(self, object_type, title, singer, category):
        print('Document class init called')
        super().__init__(object_type, title)  
        self.singer = singer 
        self.category = category
    def get_context_length(self): 
        return "此音乐时长是4分18秒"
if __name__ == '__main__':
    doc = Document("docx", "Python教程", "chunming", "写给测试人员的Python教程")
    print(doc)
    print(doc.get_context_length())
    video = Video('mp4', "Python视频教程")  
    print(video)
    print(issubclass(Video, Entity))
    print(video.get_context_length())

       Entity是父类,Document和Video是继承自Entity的子类,他们都继承了父类的object_type和title属性,以及get_context_length方法。Document还有自己的独特属性author和__context。Document类的get_context_length方法覆盖了父类的方法。

       当子类调用父类的方法时,可以通过super(子类,self)方式。看看官网中super的介绍:

class super(object)
| super() -> same as super(class, )
| super(type) -> unbound super object
| super(type, obj) -> bound super object; requires isinstance(obj, type)
| super(type, type2) -> bound super object; requires issubclass(type2, type)
| Typical use to call a cooperative superclass method:
| class C(B):
| def meth(self, arg):
| super().meth(arg)
| This works for class methods too:
| class C(B):
| @classmethod
| def cmeth(cls, arg):
| super().cmeth(arg)

       从定义中可以看到,通常用来调用对应的父类的方法。super() 与 super(子类,self)的方式是等价的,他们都会返回一个父类对象。

       判断一个类是不是另外一个类的子类,可以通过issubclass判断。

       2.2 多继承

       虽然可以,但是尽量不用。

       2.3 object和type的关系

       在面向对象体系里面,存在两种关系:

  • 继承关系,可以通过__bases__属性可以类的所有父类(因为Python支持多继承)。

  • 类与实例关系,可以通过__class__属性查看实例的类型,或者使用type()函数查看。

       在Python的世界中,所有类都是object的子类;所有对象都是type的实例。

class Parent:
    pass
class Child(Parent):
    pass
if __name__ == '__main__':
    p = Parent()
    c = Child()
    print(Parent.__bases__)  # 获取Parent类的父类,输出为(<class 'object'>,)
    print(Child.__bases__)  # 获取Child类的父类,输出(<class '__main__.Parent'>,)
    print(c.__class__)  # 获取c的类型,输出<class '__main__.Child'>
    print(type(c))  # 等同于c.__class__
    print(object.__class__)  # object类是type类型,输出<class 'type'>
    print(object.__bases__)  # object类 无父类,输出为()
    print(type.__class__)  # type类是type类型,输出<class 'type'>
    print(type.__bases__)  # type类 的父类是object类,输出为(<class 'object'>,)
    print(list.__class__)  # list类是type类型,输出<class 'type'>
    print(list.__bases__)  # list类的父类是object类,输出(<class 'object'>,)
    print(tuple.__class__)  # tuple类是type类型,输出<class 'type'>
    print(tuple.__bases__)  # tuple类的父类是object类,输出(<class 'object'>,)
    print(dict.__class__)  # dict类是type类型,输出<class 'type'>
    print(dict.__bases__)  # dict类的父类是object类,输出(<class 'object'>,)

       可见object类、type类、list类、tuple类、dict类都是type类型,也就是说是type类的实例。type类、list类、tuple类、dict类的父类都是object类,object类本身没有父类。

      3、多态很方便

       还是用上面的例子,学多态的应用。在main里面,实例化三个类,并且定义了一个统一的接口来访问实例的方法。

if __name__ == '__main__':
    doc = Document("docx", "Python教程", "chunming", "写个测试人员的Python教程")
    music = Music('mp4', "风吹麦浪", "李键", "抒情")
    video = Video('mp4', "Python视频教程")
    # print(doc.get_context_length())
    # print(music.get_context_length())
    def get_length(entity):  # 统一接口,根据传进来的实例类型自动找到它的方法执行
        print(entity.get_context_length())   # 访问实例的方法。
    get_length(doc)
    get_length(music)
    get_length(video)

       这就是多态,指在不考虑实例类型的情况下使用实例的方法。通过这个例子,能够直观感受到多态的优点:

  • 增加了程序的灵活性

       以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如get_length(picture)

  • 增加了程序额可扩展性

       通过继承Entity类创建了一个新的类Picture,使用者无需更改自己的代码,还是用get_length(picture)去调用

class Picture:
    def __init__(self, photographer, pixel):
        self.photographer = photographer
        self.pixel = pixel
    def get_context_length(self):  # 声明同样的方法
        return "像素是 {}".format(self.pixel)

       这种行为称为多态。也就是说,get_length()方法调用将作用在 参数entity的实际类型上。entity是Document类型,它实际上拥有自己的 get_context_length()方法以及从 Entity类继承的 get_context_length()方法,但调用 entity.get_context_length()总是先查找它自身的定义,如果没有定义,则顺着继承链向上查找,直到在某个父类中找到为止,例如上面例子中的video。

       由于Python是动态语言,所以,传递给函数get_length()的参数 entity 不一定是 Entity 或 Entity 的子类型。任何数据类型的实例都可以,只要它有一个get_context_length()的方法即可。


作者:liuchunming033

原文链接:https://blog.csdn.net/liuchunming033/article/details/107956591#comments_13222935

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • SeleniumBase是一个自动化web测试框架,它的设计pyse相似,基于selenium和unittest封装的框架,api多,支持命令行多参数执行文档地址:https://github.com/seleniumbase/SeleniumBase下载pip下载 pip install seleniumbasegit克隆git clone https://github.com/seleniumbase/SeleniumBase.git cd SeleniumBase pip install -r require...
            0 0 1308
            分享
          •   测试一个新功能时,最重要的一个步骤就是编写测试用例,测试用例写好了,那么后面的测试工作基本就非常顺利了,那么作为一个职场新人来说,怎样提高测试用例的质量呢?  充分理解需求  作为一个新人来说,对所做项目并没有太深入的了解,那么拿到测试需求后,不应该拿到什么就是什么,需求上怎么写就怎么做,要有自己的见解。  举个例子来说,某个网站年终大促,要搞个优惠活动,有两种优惠方式:  第一种是店铺自己发的优惠,两件8折、3件7折;  另一种是平台提供的优惠,满100-10、200-30。  测试人员A拿到这个需求后,发现非常简单,迅速的就将测试用例编写完了,如下:  乍一看是没有问题的,所有情况也都...
            0 0 1118
            分享
          •   随着金三银四的来临,经济的复苏,各行各业也在复苏,相信无论是即将毕业的大学生,还是想换工作的小伙伴,想必都蠢蠢欲动。  但想找到一份适合自己的工作,实际上没有想像中的那么简单。  想做或是喜欢的工作  你要明白自己想要从事或是喜欢做的行业是什么。很多即将毕业或是已经好多年的小伙伴,一直不知道自己想要从事什么样的工作。  面包前面,随便选择了一份自己也不知道是什么的工作,等到醒悟过来的时候,又觉得自己没有能力改行,就这样,在一份自己没有兴趣的工作中浑浑噩噩好多年,浪费了好多时间。虽说面包很重要,为了目前的面包,可以做暂时的妥协,但自己也要清楚自己在多长时间后可以做自己喜欢的事情。  一份自己...
            0 0 493
            分享
          •   1、添加Jdbc Request  2、添加ForEach控制器(右键线程组->逻辑控制器->ForEach控制器)  ①输入变量的前缀:mobilephone;  从jdbc request设置的变量得知,我们要取的值为mobilephone_1、mobilephone_2、mobilephone_3......所以这里输入mobilephone  ②Start index for loop:0  变量循环启动的索引,第一个元素起始索引+1End index for loop:6;变量循环结束的索引。所以这里是取值mobilephone_1、mobilephone_2、......
            0 0 632
            分享
          •   本文是一篇利用AI生成测试用例的实战内容,包括AI原理及测试用例生成过程两方面,接下来先看看测试界面及生成的测试用例效果展示。  一 训练结果  测试页面  下图这是我的测试页面:  AI模型生成的测试用例:  二 Kimi AI 模型介绍  地址:https://kimi.moonshot.cn/chat/cnjrkho3r0737glhtm80  Kimi AI模型是由月之暗面科技有限公司(Moonshot AI)开发的智能助手。它的核心能力在于处理长文本,支持长达20万汉字的输入,这在全球大模型产品中是一个显著的特点。Kimi AI能够处理多种类型的文件和来自不同网站的内容,包括PD...
            0 0 1659
            分享
      • 51testing软件测试圈微信