![18b2c5a6f52a0a0f3d5ee48728eba5b3.png](https://img-blog.csdnimg.cn/img_convert/18b2c5a6f52a0a0f3d5ee48728eba5b3.png)
Python是做自动化工作首选的一门语言,与更复杂的语言相比,Python 非常便于快速学习、语法很少,具有良好的 可读性,即使测试工程师们没有丰富的编码经验,也能快速学会;Python 的极简风格对于测试自动化具有诸多优势,测试步骤在本质上是呈线性的、一 次执行一个,按顺序执行,配合丰富的插件,非常适合测试脚本的开发。
本文主要介绍python中面向对象的思想、类的创建及调用以及在python中的面向对象三大特性实现。
一、面向对象思想
面向对象编程(Object Oriented Programming,简称OOP),是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因不仅因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
1、面向对象和面向过程
面向对象(Object Oriented,简称OO),是一种程序设计思想,如python和java语言就是一种面向对象的编程语言:
- OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
- OOP把程序看做不同对象的相互调用 - OOP的抽象程度比函数要高
面向过程(Procedure Oriented 简称PO),也是一种常见的程序设计思想,如c语言:
- 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
- 面向过程编程是把函数看着程序的最基本单元,一个函数包括要处理的数据及算法逻辑
- 面向过程编程是把程序看作不同函数之间的互相调用
- 面向过程编程的抽象层度相对较低
- 优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可
- 缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
![7020738dbd42970d953b3d48c6cf7e43.png](https://img-blog.csdnimg.cn/img_convert/7020738dbd42970d953b3d48c6cf7e43.png)
2、面向对象的常见概念
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法,对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,类属性是用变量来表示的。这种变量就称为实例变量,一般使用self.variableName。
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数,类中的方法必须有一个参数self,也必须是在位置参数的第一位。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写
二、类的创建及调用
1、类的创建
使用 class 关键字来创建一个新类,class 之后为类的名称()并以冒号结尾:
class ClassName():
'''类的帮助信息'''
类体,包括类的变量和方法
类的帮助信息可以通过ClassName. doc查看。
下面写一个动物类的案例:
class Animal():
#这些都是类变量,在类中,方法外
nicheng = "动物"
#类中的方法参数中必须要有一个self,而且必须是在位置参数的第一位
#实例(对象)变量,在变量前需要有一个self.
def info(self):
self.age = 0
self.gender = "male"
self.weight = 0
self.brand = "xxx"
def eat(self):
print("站着吃")
def sleep(self):
print("趴着睡")
2、类对象的创建及使用
A=className()
- 类对象支持两种操作:属性引用和方法引用
- 标准语法:obj.name
针对上文动物类的对象创建及使用:
# 创建对象pig,及使用对象的变量和方法
pig = Animal()
# cat = Animal()
# print(pig.age)
# print(cat.age)
# cat.sleep()
# cat.info()
print(Animal.nichen)
3、构造方法的使用
- 构造方法可以实现对实例变量的初始化操作
- init的特殊方法(构造方法),在类实例化时会自动调用
- init方法可以有参数,参数通过 init传递到类的实例化操作上
- 可以不显示地写init方法,会默认使用无参数的构造方法
- 如果显示地写了构造方法,则不能再使用无参数的构造方法
class studentInit():
#声明类变量
type1 = '学生'
#通过构造方法实现对实例变量的初始化
def __init__(self,age,name,ID):
#定义并对实例变量进行初始化
self.age = age
self.name = name
self.ID = ID
#定义第一个方法info,实现对实例变量的初始化
def info(self):#显示对象属性的方法
print("年龄是%d、姓名是%s、学号是%s"%(self.age,self.name,self.ID))
def study(self):
score=80
self.ID = "0000000"
print("学生%s的学习成绩是:%d"%(self.ID,score))
def play(self):
print("学习之余需要玩会游戏!")
#创建类的对象(实例化:由抽象到具体)
#如果你显示地写了带参数的构造方法,则不再允许使用默认的无参数的构造方法
# TypeError: __init__() missing 3 required positional arguments: 'age', 'name', and 'ID'
xiaohua = studentInit(20,"xiaohua","12345678")
print(xiaohua.type1)
print(xiaohua.age)
xiaohua.play()
xiaohua.study()
4、self的使用
- 类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
- self不是关键字,你可以把它改成其他名称,虽然代码能正常运行,但是还是会提示:Method should have "self" as first argument
def addition(self):
print(self)
print(self.__class__)
输出结果为:
<__main__.Number object at 0x000001CD5E369E08>
<class '__main__.Number'>
- 一般我们也不会这么干,因为你写了,别人都不一定知道是啥意思,大家都已经形成习惯了
- self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类
def addition(this):
print(this)
print(this.__class__)
输出结果为:
<__main__.Number object at 0x000001CD5E369E08>
<class '__main__.Number'>
三、面向对象的三大特性
三大特性包括:
- 封装
- 继承
- 多态
1、封装
对于私有的属性,不能被外界使用,但不可避免的要被访问和修改,我们就提供一些方法进行修改和对外访问接口,这种方式叫做封装 - 将变化隔离 - 提高复用性 - 提高安全性
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)。
- __private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部直接访问,在类内部的方法中使用时self.private_attrs
- __private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用self.private_methods,不能在类的外部调用
class Student():
def __init__(self,name,age,sex):
self.__name = name
self.__age = age
self.__sex = sex
one = Student('allen',18,'男')
# print(one.__name) # 报错,无该属性
# print(one.name) # 报错,无该属性
print(one._Student__name)
print(one._Student__age)
print(one._Student__sex)
one._Student__age = 20
print(one._Student__age)
此时发现,我们虽然不能使用one.name或者one.name访问到该属性。但是我们可使用one._Studentage访问到对象的age属性并且能修改。说明python在设置私有属性的时候,只是把属性的名字换成了其他的名字。
- 将变量私有化后,还需要对外提供公共的访问方式:
Student():
def __init__(self,name,age,sex):
self.__name = name
self.__age = age
self.__sex = sex
def get_name(self):
return self.__name
def set_name(self,name):
if len(name) > 1 :
self.__name = name
else:
print("name的长度必须要大于1个长度")
def get_age(self):
return self.__age
def set_age(self, age):
if age > 0 and age < 150:
self.__age = age
else:
print("输入的年龄必须要大于0,小于150岁")
one = Student('plf',18,'男')
one.set_name('a') # 通过自己设置接口,可以有效规避脏数据
print(one.get_name()) # 通过接口获取数据
one.set_age(-9) # 通过自己设置接口,可以有效规避脏数据
print(one.get_age()) # 通过接口获取数据
- 除此之外还可以使用 @property 装饰器提供私有数据的访问
class Student():
def __init__(self,name,age,sex):
self.__name = name
self.__age = age
self.__sex = sex
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
if len(name) > 1 :
self.__name = name
else:
print("name的长度必须要大于1个长度")
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
if age > 0 and age < 150:
self.__age = age
else:
print("输入的年龄必须要大于0,小于150岁")
one = Student('plf',18,'男')
one.name = '张三'
print(one.name)
one.age = 170
print(one.age)
2、继承
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
继承,其实这样理解,就是我写了一个爸爸类和儿子类,爸爸有钱,儿子却没钱,于是儿子决定继承爸爸,调用爸爸的钱(爸爸类的变量和方法)。
- 面向对象的编程带来的主要好处之一是代码的重用,通过继承机制实现
- 通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类
- 继承的实现必须基于类的“继承”关系
![43ec4865125b18432c6af1d948cc4180.png](https://img-blog.csdnimg.cn/img_convert/43ec4865125b18432c6af1d948cc4180.png)
继承语法是:
class 派生类名(基类名):
类的代码
...
下面是一个实现继承的案例:
#引入继承的理念:提取不同类中共有的属性和行为:年龄、性别、颜色、吃鱼、睡、玩
在python中继承中的一些特点:
- 如果在子类中需要父类的构造方法就需要显式的调用父类的构造方法,或者不重写父类的构造方法。
- 在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。
class Parent(): # 定义父类
parentAttr = 100
def __init__(self):
print("调用父类构造函数")
def parentMethod(self):
print('调用父类方法')
class Child(Parent): # 定义子类
def __init__(self):
print("调用子类构造方法")
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print("父类属性 :", Parent.parentAttr)
def childMethod(self):
Parent.parentMethod(self)
print('调用子类方法')
c = Child() # 实例化子类
c.childMethod() # 调用子类的构造方法
c.parentMethod() # 调用父类方法
c.setAttr(200) # 调用字类方法修改父类属性 - 设置属性值
c.getAttr() # 调用字类方法查看父类属性 - 获取属性值
===运行结果======
调用子类构造方法
调用父类方法
调用子类方法
调用父类方法
父类属性 : 200
- python中类的继承分为:单继承(子继承父)和多继承(子继承父、母),而且支持多层继承(子继承父、父继承祖父)
class A(): # 定义类 A
def aa(self):
print("我是A")
class B(): # 定义类 B
def bb(self):
print("我是C")
class C(A, B): # C继承类 A 和 B
def cc(self):
print("我是C")
class D(A): # D继承类A
def dd(self):
print("我是D")
class F(D):
def ff(self):
print("我是F")
#python支持单继承、多继承和多层继承
f = F()
f.aa()
#会报错,没有继承关系
# f.bb()
- 方法重写,如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法:
class Parent(): # 定义父类
def myMethod(self):
print('调用父类方法')
class Child(Parent): # 定义子类
pass
# def myMethod(self):#字类重写父类的同名方法
# print('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法,如果不重写,则调用父类方法
3、多态
Java中多态性,可以理解为一个事物的多种形态,比如我们说猫是动物、猫也是猫,猫就具备了不同的形态。同样python中也支持多态,但是是有限的的支持多态性,主要是因为python中变量的使用不用声明,所以不存在父类引用指向子类对象的多态体现,同时python不支持重载。在python中 多态的使用不如Java中那么明显,所以python中刻意谈到多态的意义不是特别大。
Python中多态的特点 :
- 只关心对象的实例方法是否同名,不关心对象所属的类型;
- 对象所属的类之间,继承关系可有可无;
- 多态的好处可以增加代码的外部调用灵活度,让代码更加通用,兼容性比较强;
- 多态是调用方法的技巧,不会影响到类的内部设计。
class Animal():
def run(self):
print("Animal Running ……")
class Cat(Animal):
def run(self):
print("Cat Running ……")
class Dog(Animal):
def run(self):
print("Dog Running ……")
def runTwice(animal):
animal.run()
a = Animal()
c = Cat()
d = Dog()
runTwice(a)
runTwice(c)
runTwice(d)
===运行结果======
Animal Running ……
Cat Running ……
Dog Running ……
鸭子多态:
- 当我们需要传入Dog、Cat等不同子类时,我们只需要接收Animal类型就可以了,因为Dog、Cat都是Animal类型,然后按照Animal类型进行操作即可,由于Animal有run方法,因此传入的任意类型,只要是Animal或其子类,就会自动调用实际类型的run方法
- 对于静态语言(Java)来说,如果需要传入Animal类型,则形参必须是Animal或其子类对象,否则无法调用run方法
- 对于动态语言(Python)来说,则不一定要传入Animal类型,我们只需要保证传入的对象包括run方法即可
- 这就是动态语言的“鸭子类型”,他并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子,那他就可以被看做是鸭子!”
欢迎关注作者,如果觉得写的还不错,就给点个赞同、喜欢、收藏(后续持续更新)。
【全文手打 如需转载 请标注此出处】
![faff8c230a0cbf19f71f17f34a70d539.png](https://img-blog.csdnimg.cn/img_convert/faff8c230a0cbf19f71f17f34a70d539.png)