文章目录
- 一、引言
- 二、类
- 三、面向对象的三大特征
- 1.继承
- 2.多态
- 3.其他
一、引言
在上一篇文章中,我们以就面向对象编程进行了简单的介绍,这一章主要是进行一些细致补充与拓展,这部分内容在初学python时就已经学到了,现在回顾,没有做到学与用的结合,切记!!!
二、类
- 1.类的定义
python中“一切皆对象”。类称为类对象,类的实例称为实例对象。
- 2.构造函数__init__
一个python对象含以下部分:
- 3.实例属性
实例属性是从属于实例对象的属性
要点:
- 4.实例方法
实例方法是从属于实例对象的方法。
定义格式:
函数和方法的区别:
例子:
class Bettery():"""模拟电动汽车的电池"""def __init__(self, bettery_size=70):self.bettery_size = bettery_size # 电池容量self.electric_quantity = bettery_size # 电池剩余容量self.electric_distance_ratio = 5 # 电量距离换算系数self.remainder_range = self.electric_quantity *self.electric_distance_ratio # 剩余可行驶距离def get_electric_quantity(self):"""查看当前容量"""print("当前电池剩余电量:{}kw.h".format(self.electric_quantity))def set_electric_quantity(self, electric_quantity):"""设置电池剩余电量,重新计算电量可支撑行驶里程"""if electric_quantity > 0 and electric_quantity < self.bettery_size:self.electric_quantity = electric_quantityself.remainder_range = self.electric_quantity * self.electric_distance_ratioelse:print("电量未设置在合理范围内!")def get_remainder_range(self):"""查看剩余可行驶里程"""print("当前电量还可以继续行驶{}公里".format(self.remainder_range))class Car():"""模拟汽车"""def __init__(self, brand, model, year):"""初始化汽车属性"""self.brand = brand # 品牌self.model = model # 型号self.year = year # 出厂年份self.mileage = 0 # 里程碑数def get_main_information(self): # self不能省"""获取汽车主要信息"""print("品牌:{},型号:{},出厂年份:{}".format(self.brand, self.model,self.year))def get_all_mileage(self):"""获取总里程数"""return "行车总里程:{}公里".format(self.mileage)class ElectricCar(Car):"""模拟电动汽车"""def __init__(self, brand, model, year, bettery_size):"""初始化电动汽车属性"""super().__init__(brand, model, year)self.bettery = Bettery(bettery_size) # 电池def get_main_information(self): # 重写父类方法"""获取电动车的主要信息"""print("品牌:{} 型号:{} 出厂年份:{} 续航里程数:{}公里".format(self.brand, self.model, self.year,self.bettery.bettery_size * self.bettery.electric_distance_ratio))my_electric_car = ElectricCar("NextWeek", "FF91", 2046, 70)
# 获取车辆主要信息
my_electric_car.get_main_information()
# 获取当前电池量
my_electric_car.bettery.get_electric_quantity()
# 重设电量
my_electric_car.bettery.set_electric_quantity(50)
# 获取当前电量
my_electric_car.bettery.get_electric_quantity()
# 获取当前剩余可行驶里程数
my_electric_car.bettery.get_remainder_range()# 获得对象的所有属性与方法
print(dir(my_electric_car))
# 获得对象的属性字典
print(dir(my_electric_car.__dict__))
# 判断对象是不是指定类型
print(isinstance(my_electric_car,ElectricCar))# 品牌:NextWeek 型号:FF91 出厂年份:2046 续航里程数:350公里
# 当前电池剩余电量:70kw.h
# 当前电池剩余电量:50kw.h
# 当前电量还可以继续行驶250公里
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bettery', 'brand', 'get_all_mileage', 'get_main_information', 'mileage', 'model', 'year']
# ['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
# True
创建过程
实例化对象时,先通过__new__创建对象,然后将对象地址传给__init__中的self参数,__init__用于初始化创建好的对象,最后再将创建好的对象地址返回给相应变量。
5.类对象
当解释器执行class语句时,就会创建一个类的类型对象(type)
class Student: #创建Student类的类型对象(type)def __init__(self,name,score):self.name = nameself.score = scoredef say_score(self):print("{0}的分数是{1}".format(self.name,self.score))stu = Student #指向同一个类对象
s1 = stu("柳杰","100")
s2 = stu("谈昊田","99")
print(s1)
print(s2)
s1.say_score()
s2.say_score()
>>>
<__main__.Student object at 0x000001FE3C28F160>
<__main__.Student object at 0x000001FE3C28F128>
柳杰的分数是100
谈昊田的分数是99
6.类属性
类属性从属于类对象,可以被所有实例对象共享。
在类中或者类的外面,可以通过类名.类变量名来读写
类属性常用于计数(实例对象创建的数量),如下:
内存分析:
7.类方法
#类方法只存在于Student类的类型对象里,而不存在于实例对象里
class Student:company = "SXT"@classmethoddef printCompany(cls):print(cls.company)Student.printCompany()
>>>
SXT
8.静态方法
class Student:commpany = "SXT"@staticmethoddef add(a,b):print("{0}+{1}={2}".format(a,b,(a+b)))Student.add(5,6)
>>>
5+6=11
9.__del__析构方法
#析构方法测试
class Person:def __del__(self):print("销毁对象:{0}".format(self))p1 = Person()
p2 = Person()
>>>
销毁对象:<__main__.Person object at 0x000001C3C9266940>
销毁对象:<__main__.Person object at 0x000001C3C955A048>
内存分析
#析构方法测试
class Person:def __del__(self):print("销毁对象:{0}".format(self))p1 = Person()
p2 = Person()
del p1
del p2
>>>
销毁对象:<__main__.Person object at 0x000001C3C9266940>
销毁对象:<__main__.Person object at 0x000001C3C955A048>
10.__call__方法
定义了__call__方法的对象,称为可调用对象。即该对象可以像函数一样被调用
# 测试可调用方法__call__
class SalaryAccount:def __call__(self,salary):print("算工资啦!")monthsalary = salaryyearsalary = salary * 12daysalary = salary/22.5hoursalary = daysalary/8return dict(yearsalary = yearsalary,monthsalary = monthsalary,daysalary = daysalary,hoursalary = hoursalary)s = SalaryAccount()
print(s(15000))
>>>
算工资啦!
{'yearsalary': 180000, 'monthsalary': 15000, 'daysalary': 666.6666666666666, 'hoursalary': 83.33333333333333}
11.方法没有重载
12.方法的动态性
# 测试方法的动态性-方法是对象,函数是对象,一切皆对象
class Person:def work(self):print("好好上班!!!")def playGame(s):print("{}在玩游戏!".format(s))
def work2(s):print("好好工作,努力上班,赚大钱,娶媳妇!!!")p = Person()
p.work()
Person.play = playGame #为类添加新的方法
p.play() #Person.play(p)Person.work = work2 #动态地修改类已有的方法
p.work()
>>>
好好上班!!!
<__main__.Person object at 0x000001C34848F160>在玩游戏!
好好工作,努力上班,赚大钱,娶媳妇!!!
13.私有属性和私有方法(实现封装)
要点:
注:方法本质上也是属性,只不过是可以通过()来执行。
# 测试私有属性
class Employee:def __init__(self, name, age):self.name = nameself.__age = age #私有属性e = Employee("柳杰", "23")
# print(e.__age) #__age属性私有化,'Employee' object has no attribute 'age'
print(e._Employee__age) #访问私有属性
print(dir(e))
>>>
23
['_Employee__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
# 测试私有方法
class Employee:def __init__(self, name, age):self.name = nameself.__age = agedef __work(self): #私有方法print("好好工作,努力上班,赚大钱,娶媳妇!!!")print("年龄:{}".format(self.__age)) # 类内部可以访问私有属性(或方法)e = Employee("柳杰", "23")
# e.__work() #AttributeError: 'Employee' object has no attribute '__work'
e._Employee__work()
>>>
好好工作,努力上班,赚大钱,娶媳妇!!!
年龄:23
14.@property装饰器_get和set方法
@property可以将一个方法的调用方式变成了“属性调用”。
# 方法的调用
class Employee:def __init__(self,name,salary):self.__name = nameself.__salary = salarydef getSalary(self):return self.__salarydef setSalary(self,salary):if 1000 < salary <= 50000:self.__salary = salaryelse:print("工资录入错误!!!薪水应该在1000-50000之间")e = Employee("柳杰","25000")
print(e.getSalary())
e.setSalary(30000)
print(e.getSalary())
>>>
25000
30000
# 测试@property装饰器的用法-属性的调用
class Employee:def __init__(self,name,salary):self.__name = nameself.__salary = salary@propertydef salary(self):return self.__salary@salary.setterdef salary(self,salary):if 1000 < salary <= 50000:self.__salary = salaryelse:print("工资录入错误!!!薪水应该在1000-50000之间")
e = Employee("柳杰","25000")
print(e.salary)
e.salary = 30000
print(e.salary)
>>>
25000
30000
三、面向对象的三大特征
三大特征:继承、封装、多态
- 继承:继承可以让子类具有父类的特性,提高代码的重用性。 在原有父类设计不变的情况下,可以增加新功能或改进已有算法
- 封装:隐藏对象的属性和实现细节,只对外提供必要的方法。 通过私有属性、私有方法进行封装,更多依靠程序员自觉完成
- 多态:是指同一种方法调用由于对象不同会产生不同的行为
1.继承
class Person:def __init__(self,name,age):self.name = nameself.__age = age #私有属性def sayAge(self):print("年龄,年龄,我也不知道!!!")
class Student(Person):def __init__(self,name,age,score):Person.__init__(self,name,age) # 必须显式的调用父类的方法,不然解释器不会去调用self.score = scores = Student("柳杰","23","100")
s.sayAge()
print(s.name)
print(dir(s))
print(s._Person__age) # 必须用访问私有属性的方法,访问父类里的私有属性
>>>
年龄,年龄,我也不知道!!!
柳杰
['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'sayAge', 'score']
23
1)类成员的继承和重写
# 测试继承的基本使用
class Person:def __init__(self,name,age):self.name = nameself.__age = age #私有属性def sayAge(self):print("我的年龄是",self.__age)def sayIntroduce(self):print("我的名字是",self.name)
class Student(Person):def __init__(self,name,age,score):Person.__init__(self,name,age) #必须显式的调用父类的方法,不然解释器不会去调用self.score = scoredef sayIntroduce(self):'''重写了父类的方法'''print("报告老师!我的名字是{}".format(self.name))s = Student("柳杰","23","100")
s.sayAge()
s.sayIntroduce()
print(Student.mro()) #print(Student.__mro__)输出这个类的继承层次结构
>>>
我的年龄是 23
报告老师!我的名字是柳杰
[<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]
2)查看类的层次结构
通过类的方法mro()或者类的属性__mro__输出这个类的继承层次结构
3)object根类
object类是所有类的父类,因此所有类都有object类的属性和方法
4)重写__str__方法
# 测试重写object对象的__str__()
class Person:def __init__(self,name):self.name = namedef __str__(self):return "名字是{}".format(self.name)
p = Person("柳杰")
print(p)
>>>
名字是柳杰
5)多重继承
**MRO方法解析顺序:**广度优先算法
6)super()获得父类定义
# 测试super()代表父类的定义,而不代表父类的对象
class A:def say(self):print("A:",self)
class B(A):def say(self):super(B, self).say() #A.say()print("B:",self)
B().say()
>>>
A: <__main__.B object at 0x00000131F855BFD0>
B: <__main__.B object at 0x00000131F855BFD0>
2.多态
# 多态
class Man:def eat(self):print("饿啦,吃饭了!!!")
class Chinese(Man):def eat(self):print("中国人用筷子吃饭!!!")
class English(Man):def eat(self):print("英国人用叉子吃饭!!!")
class India(Man):def eat(self):print("印度人用右手吃饭!!!")def manEat(m):if isinstance(m,Man):m.eat()else:print("传入错误!!!")manEat(Chinese()) #同一方法调用,由于对象不同可能产生不同的行为
manEat(English())
manEat(India())
>>>
中国人用筷子吃饭!!!
英国人用叉子吃饭!!!
印度人用右手吃饭!!!
3.其他
1)特殊方法和运算符重载
# 测试运算符的重载
class Person:def __init__(self,name):self.name = namedef __add__(self,other):if isinstance(other,Person):return "{0}--{1}".format(self.name,other.name)else:return "不是同类对象,不能相加!!!"def __mul__(self, other):if isinstance(other,int):return self.name * otherelse:return "不是同类对象,不能相乘!!!"p1 = Person("柳杰")
p2 = Person("谈昊田")
x = p1 + p2
print(x)
print(p1*5)
print(x*5)
>>>
柳杰--谈昊田
柳杰柳杰柳杰柳杰柳杰
柳杰--谈昊田柳杰--谈昊田柳杰--谈昊田柳杰--谈昊田柳杰--谈昊田
2)特殊属性
3)对象的浅拷贝和深拷贝
# 测试浅拷贝和深拷贝
# 组合关系
import copy
class MobilePhone:def __init__(self,cpu,screen):self.cpu = cpuself.screen =screenclass CPU:def calculate(self):print("算你个12345")print("cpu对象:",self)
class Screen:def show(self):print("显示一个好看的图片")print("screen对象:",self)
print("测试浅复制")
#测试浅拷贝
c1 = CPU()
s1 = Screen()
m1 = MobilePhone(c1,s1)
m2 = copy.copy(m1)
print(m1,m1.cpu,m1.screen)
print(m2,m2.cpu,m2.screen)print("测试深拷贝")
#测试深拷贝
m3 = copy.deepcopy(m1)
print(m1,m1.cpu,m1.screen)
print(m3,m3.cpu,m3.screen)
>>>
测试浅复制
<__main__.MobilePhone object at 0x00000106A796C4E0> <__main__.CPU object at 0x00000106A796C4A8> <__main__.Screen object at 0x00000106A796C128>
<__main__.MobilePhone object at 0x00000106A79730F0> <__main__.CPU object at 0x00000106A796C4A8> <__main__.Screen object at 0x00000106A796C128>
测试深拷贝
<__main__.MobilePhone object at 0x00000106A796C4E0> <__main__.CPU object at 0x00000106A796C4A8> <__main__.Screen object at 0x00000106A796C128>
<__main__.MobilePhone object at 0x00000106A796F048> <__main__.CPU object at 0x00000106A89E79B0> <__main__.Screen object at 0x00000106A89E7DA0>
4)组合
# 测试组合
class A:def say_a(self):print("我是a,a,a")
class B:def __init__(self,a): # 把a的对象作为属性self.a = a
a = A()
b = B(a)
b.a.say_a()
>>>
我是a,a,a
# 测试has-a关系,使用组合
class MobilePhone:def __init__(self,cpu,screen):self.cpu = cpuself.screen =screenclass CPU:def calculate(self):print("算你个12345")print("cpu对象:",self)
class Screen:def show(self):print("显示一个好看的图片")print("screen对象:",self)c1 =CPU()
s1 = Screen()
m1 = MobilePhone(c1,s1) # 组合的关系
m1.cpu.calculate()
m1.screen.show()
>>>
算你个12345
cpu对象: <__main__.CPU object at 0x00000233DA93C128>
显示一个好看的图片
screen对象: <__main__.Screen object at 0x00000233DA93C4A8>
5)工厂模式
工厂模式实现创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进行统一管理
# 测试工厂模式
class CarFactory:def creat_car(self,brand): #对创建对象进行管理if brand == "奔驰":return Benz()if brand == "宝马":return BMW()if brand == "比亚迪":return BYD()else:return "未知品牌,无法创建"class Benz:pass
class BMW:pass
class BYD:passfactory = CarFactory()
c1 = factory.creat_car("奔驰")
c2 = factory.creat_car("比亚迪")
print(c1)
print(c2)
>>>
<__main__.Benz object at 0x000001CED3F7C470>
<__main__.BYD object at 0x000001CED3F7C4A8>
6)单例模式
# 测试单例模式
class MySingleton:__obj = None #类属性__init_flag = True #标志,控制只进行一次初始化的属性def __new__(cls, *args, **kwargs):if cls.__obj == None:cls.__obj = object.__new__(cls)return cls.__objdef __init__(self,name):if MySingleton.__init_flag:print("init....")self.name = nameMySingleton.__init_flag = Falsea = MySingleton("aa")
b = MySingleton("bb")
print(a)
print(b)
>>>
init....
<__main__.MySingleton object at 0x000001EFE206BFD0>
<__main__.MySingleton object at 0x000001EFE206BFD0>
# 工厂模式和单例模式整合使用
class CarFactory:__obj = None # 类属性__init_flag = True # 标志def __new__(cls, *args, **kwargs):if cls.__obj == None:cls.__obj = object.__new__(cls)return cls.__objdef __init__(self):if CarFactory.__init_flag:print("init....")CarFactory.__init_flag = Falsedef creat_car(self,brand):if brand == "奔驰":return Benz()if brand == "宝马":return BMW()if brand == "比亚迪":return BYD()else:return "未知品牌,无法创建"
class Benz:pass
class BMW:pass
class BYD:pass
ggmian
c1 = CarFactory()
c2 = CarFactory()
print(c1)
print(c2)
>>>
init....
<__main__.CarFactory object at 0x0000022CCF59C128>
<__main__.CarFactory object at 0x0000022CCF59C128>