什么是类?
类明明的话,大驼峰小驼峰如:BigBoss
类属性:成员都具备的特质
实例属性:一般放在init中初始化
class People(Object):
weight = 188
def __init__(self,name):
self.name = name
pass
这个Peole就是一个类
weight就是类属性,使用People.weight
来获取
什么是对象?
p = People("xiaoming")
这个p就是对象
p.name就是其中一个实例属性
基础的知识点在这里就不重复说了
类的特点就是封装继承和多态
__init__ __del__
每次我们创建对象之后,python解释器就会自动调用__init__
方法;
当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法
创建对象时,此对象的引用计数就会+1
当有1个变量保存了对象的引用时,此对象的引用计数就会加1
当使用del删除变量指向的对象时,如果对象的引用计数不会1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除
import time
class Animal(object):
# 初始化方法
# 创建完对象后会自动被调用
def __init__(self, name):
print('__init__方法被调用')
self.__name = name
# 析构方法
# 当对象被删除时,会自动被调用
def __del__(self):
print("__del__方法被调用")
print("%s对象马上被干掉了..."%self.__name)
我们可以执行一下代码,验证如下问题:
# 创建对象
dog = Animal("哈皮狗")
# 删除对象
del dog
cat = Animal("波斯猫")
cat2 = cat
cat3 = cat
print("---马上 删除cat对象")
del cat
print("---马上 删除cat2对象")
del cat2
print("---马上 删除cat3对象")
del cat3
结果如下:
继承
class Animal(object):
def __init__(self, name='动物', color='白色'):
self.__name = name
self.color = color
def __test(self):
print(self.__name)
print(self.color)
def test(self):
print(self.__name)
print(self.color)
class Dog(Animal):
def dogTest1(self):
#print(self.__name) #不能访问到父类的私有属性
print(self.color)
def dogTest2(self):
#self.__test() #不能访问父类中的私有方法
self.test()
A = Animal()
#print(A.__name) #程序出现异常,不能访问私有属性
print(A.color)
#A.__test() #程序出现异常,不能访问私有方法
A.test()
print("------分割线-----")
D = Dog(name = "小花狗", color = "黄色")
D.dogTest1()
D.dogTest2()
- 私有的属性,不能通过对象直接访问,但是可以通过方法访问
- 私有的方法,不能通过对象直接访问
- 私有的属性、方法,不会被子类继承,也不能被访问
- 一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
简而言之一句话:
私有属性可以通过方法被访问,但是不能通过对象被访问,私有属性也不能被继承
多继承的顺序。当然不知道的时候使用使用print(类名.__mro__)
一般情况下,class Son(A,B)是先继承A,之后继承B的
重写父类方法与调用父类方法
- 所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
- 不重写的话,就会直接继承
- 那一般为什么要重写呢,就是因为我们在父类的基础上有新加了一些东西,所以我们在原来的基础上,写新的东西。
- super()就是代表父类 super().方法()就代表要调用的那个方法。
#coding=utf-8
class Cat(object):
def sayHello(self):
print("halou-----1")
class Bosi(Cat):
def sayHello(self):
print("halou-----2")
bosi = Bosi()
bosi.sayHello()
- 调用父类的方法
#coding=utf-8
class Cat(object):
def __init__(self,name):
self.name = name
self.color = 'yellow'
class Bosi(Cat):
def __init__(self,name):
# 调用父类的__init__方法1(python2)
#Cat.__init__(self,name)
# 调用父类的__init__方法2
#super(Bosi,self).__init__(name)
# 调用父类的__init__方法3
super().__init__(name)
# 上面的意思就是调用父类方法中的init这个方法
def getName(self):
return self.name
bosi = Bosi('xiaohua')
print(bosi.name)
print(bosi.color)
多态
类属性和实例属性
类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有
类属性还分公有的类属性和私有的类属性
对于公有的类属性,在类外可以通过类对象和实例对象访问
如下示例:
- 类属性
class People(object):
name = 'Tom' #公有的类属性
__age = 12 #私有的类属性
p = People()
print(p.name) #正确
print(People.name) #正确
print(p.__age) #错误,不能在类外通过实例对象访问私有的类属性
print(People.__age) #错误,不能在类外通过类对象访问私有的类属性
- 实例属性(对象属性)
用类的属性方法是访问不了的
class People(object):
address = '山东' #类属性
def __init__(self):
self.name = 'xiaowang' #实例属性
self.age = 20 #实例属性
p = People()
p.age =12 #实例属性
print(p.address) #正确
print(p.name) #正确
print(p.age) #正确
print(People.address) #正确
print(People.name) #错误
print(People.age) #错误
- 通过实例(对象)去修改类属性
class People(object):
country = 'china' #类属性
print(People.country)
p = People()
print(p.country)
p.country = 'japan'
print(p.country) #实例属性会屏蔽掉同名的类属性
print(People.country)
del p.country #删除实例属性
print(p.country)
如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。
静态方法和类方法还有实例方法
实例方法很简单就是通过实例去调用方法,类方法是无法调用的,什么是类方法,如下面那个,就是Peole.方法
的形式就是类方法
类方法的话,
类方法
是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以’cls’作为第一个参数的名字,就最好用’cls’了),能够通过实例对象和类对象去访问。
- 这个cls就是class的简写
- 调用,类名.方法,实例.方法都是可以的
class People(object):
country = 'china'
#类方法,用classmethod来进行修饰
@classmethod
def getCountry(cls):
return cls.country
p = People()
print(People.getCountry())
print(p.getCountry())
结果如下:
- 类方法还有一个用途就是可以对类属性进行修改:
class People(object):
country = 'china'
#类方法,用classmethod来进行修饰
@classmethod
def getCountry(cls):
return cls.country
@classmethod
def setCountry(cls,country):
cls.country = country
p = People()
print p.getCountry() #可以用过实例对象引用
print People.getCountry() #可以通过类对象引用
p.setCountry('japan')
print p.getCountry()
print People.getCountry()
静态方法
- 需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数
- 也就是不需要self这个占位,也就是刚刚好放在类下面的普通函数,和实例的关系不大。
- 你加self那就变成了实例方法了
- 关于调用,使用self.方法和 类名.方法都是可以的
class People(object):
country = 'china'
@staticmethod
#静态方法
def getCountry():
return People.country
print People.getCountry()
总结
从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;而实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用
__new__和__init__的作用
直接总结一下吧
-
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
-
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
-
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
-
我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节
class A(object):
def __init__(self):
print("这是 init 方法")
def __new__(cls):
print("这是 new 方法")
return object.__new__(cls)
A()
结果如下:
单例模式
举个常见的单例模式例子,我们日常使用的电脑上都有一个回收站,在整个操作系统中,回收站只能有一个实例,整个系统都使用这个唯一的实例,而且回收站自行提供自己的实例。因此回收站是单例模式的应用。
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。
# 实例化一个单例
class Singleton(object):
__instance = None
def __new__(cls, age, name):
#如果类数字能够__instance没有或者没有赋值
#那么就创建一个对象,并且赋值为这个对象的引用,保证下次调用这个方法时
#能够知道之前已经创建过对象了,这样就保证了只有1个对象
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
a = Singleton(18, "dongGe")
b = Singleton(8, "dongGe")
print(id(a))
print(id(b))
a.age = 19 #给a指向的对象添加一个属性
print(b.age)#获取b指向的对象的age属性
从如下结果中可以看到,指针都是指向同一内存,改变一个实例,不管a还是b都会,都会一致的改变。
- 创建单例时,只执行1次__init__方法
# 实例化一个单例
class Singleton(object):
__instance = None
__first_init = False
def __new__(cls, age, name):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
def __init__(self, age, name):
if not self.__first_init:
self.age = age
self.name = name
Singleton.__first_init = True
a = Singleton(18, "dongGe")
b = Singleton(8, "dongGe")
print(id(a))
print(id(b))
print(a.age)
print(b.age)
a.age = 19
print(b.age)
类的一些魔法函数
def __repr__(self):
def __repr__(self):
''' 返回对象打印出来的效果,名字固定的用法'''
return self.属性
getatter()
- 获取属性,动态获取某个属性的函数
- 使用方法
- getatter(对象或者类名,属性名称,当没有这个属性的值时,需要提供一个默认值)
- getatter(对象或者类名,属性名称,当没有这个属性的值时,需要提供一个默认值)
setatter()
不管原来有没有这个属性和这个值,都会赋值给它
使用方法如下:
补充
- 只要在初始化中
__init__
定义的变量,在类的函数中,就可以直接用,不需要在函数的参数里面进行说明。
在工作中,逐渐学会了这样的一种用法:感觉很高级,但是在大神面前,那肯定不值一提。
类里面嵌套类
万物皆对象(所以类当然是啦)
- 其实这种方式有很多应用,就先记录在这里,以后用的时候,希望自己能想到。
class Upload(object):
pass
class Dotest(object):
def __init__(self):
self.upload = Upload()
有时候,我们A类里面需要使用B类很多东西的时候,又不对其进行继承,就可以使用这种初始化吧。
举一个很小的例子吧:
class Case:
"""
测试用例封装类
"""
def __init__(self):
self.id = None
self.url = None
self.data = None
self.title = None
self.method = None
self.expected = None
self.actual = None
self.result = None
class DoExcel:
file_name = None
def __init__(self, file_name):
try:
# 操作的文件
self.file_name = file_name
# 实例化一个workbooK对象
self.workbook = openpyxl.load_workbook(filename=file_name)
# 异常处理如何做
except FileNotFoundError as e:
# 文件未找到异常处理
print('{0} not found, please check file path'.format(file_name))
raise e
def get_cases(self, sheet_name):
sheet_name = sheet_name
sheet = self.workbook[sheet_name] # 获取sheet
max_row = sheet.max_row # 获取sheet最大行数
cases = [] # 定义一个列表,用来存放即将要放进去的测试用例
for r in range(2, max_row + 1): # for 循环,从第二行开始遍历
case = Case() # 实例化一个case对象,用来存放测试数据
case.id = sheet.cell(row=r, column=1).value # 取第r行,第1格的值
case.title = sheet.cell(row=r, column=2).value # 取第r行,第2格的值
case.url = sheet.cell(row=r, column=3).value # 取第r行,第3格的值
case.data = sheet.cell(row=r, column=4).value # 取第r行,第4格的值
case.method = sheet.cell(row=r, column=5).value # 取第r行,第5格的值
case.expected = sheet.cell(row=r, column=6).value # 取第r行,第6格的值
if type(case.expected) == int:
case.expected = str(case.expected)
cases.append(case) # 将case放到cases 列表里面
return cases # for 循环结束后返回cases列表
上面的代码已经做了详细的注释,主要是实现一个多个测试用例的,其实最后调用就会得到这样的数据
cases = [case{xxx1},case{xxx2},case{xxx3}...]