文章目录
第九章 面向对象
一、面向对象编程介绍
"""
1、面向过程编程
核心是“过程”二字,过程指的是做事的步骤
基于该思想编写程序就好比在设计一条条的流水线
优点:复杂的问题流程化、进而简单化
缺点:扩展性差
2、面向对象编程
核心是“对象”二字,对象是一个的容器(盛放相关的数据与功能)
基于该思想编写程序就是造一个个对象/容器
优点:扩展性强
缺点:比起面向过程来说,加重了编程的复杂度
大白话:面向对象编程的核心就是造对象/容器盛东西,该容器就是一个内存空间
"""
def choose(self):
print('<%s:%s:%s>正在选课' %(self["stu1_name"],self["stu1_age"],self["stu1_gender"]))
Student_dic={
"school":"qinghua",
"choose":choose
}
stu1_dic={
"stu1_name":"wuchangwen",
"stu1_age":18,
"stu1_gender":"male",
}
stu2_dic={
"stu1_name":"jack",
"stu1_age":19,
"stu1_gender":"female",
}
# print(stu1_dic)
# stu1_dic["choose"](stu1_dic)
# print(stu1_dic["stu1_name"])
二、 类与对象
# 什么是类?
# 类就是一个容器(一个内存空间),存放的是对象之间相同的数据与功能
# 为何要有类?
# 为了节省内存空间
"""
学生对象1
数据
学校="qinghua"
名字="wuchangwen1"
年龄=18
性别="male"
功能
选课功能
学生对象2
数据
学校="qinghua"
名字="wuchangwen2"
年龄=19
性别="female"
功能
选课功能
学生对象3
数据
学校="qinghua"
名字=wuchangwen3"
年龄=23
性别="male"
功能
选课功能
学生类
相同数据
学校="qinghua"
相同功能
选课功能
"""
#语法规定:先定义类,后调用类产生对象
class Student:
# 相同数据
school ="qinghua"
# 相同功能
def choose(self):
print('is choosing course')
# print("====>")
# 1、定义类=》把存有所有学生对象相同的数据与功能的内存空间准备好
# 类体代码会在类定义阶段立即运行,所以会产生一个类的名称空间,将类体代码运行过程中
# 产生的名字都丢到类的名称空间中,然后类名指向的就是类的名称空间
# print(Student.__dict__)
# print(Student.school) # Student.__dict__["school"]
# 2、调用类=》产生对象
# 调用类做的事情
# (1)造一个对象的内存空间,并将给内存空间与类的内存空间绑定
stu_obj1 = Student()
stu_obj2 = Student()
stu_obj3 = Student()
# print(stu_obj1)
# print(stu_obj2)
# print(stu_obj3)
# print(stu_obj1.__dict__)
# print(stu_obj2.__dict__)
# print(stu_obj3.__dict__)
# print(stu_obj1.school)
# 3、为对象初始化自己独有的属性
stu_obj1.name = "wuchangwen1" # stu_obj1.__dict__["name"]="wuchangwen"
stu_obj1.age = 18 # stu_obj1.__dict__["age"]=18
stu_obj1.gender = "male" # stu_obj1.__dict__["gender"]="male"
# print(stu_obj1.__dict__)
stu_obj2.name = "wuchangwen2"
stu_obj2.age = 19
stu_obj2.gender = "female"
stu_obj3.name = "wuchangwen3"
stu_obj3.age = 23
stu_obj3.gender = "male"
# print(stu_obj1.name)
# print(stu_obj1.age)
# print(stu_obj1.gender)
#
# print(stu_obj1.school)
# print(stu_obj1.choose)
# stu_obj2
# stu_obj3
三、 init 方法
# class Student:
# school ="qinghua"
#
# def choose(self):
# print('is choosing course')
#
# stu_obj1 = Student()
# stu_obj2 = Student()
# stu_obj3 = Student()
# 为对象初始化自己独有的属性
# stu_obj1.name = "张三" # stu_obj1.__dict__["name"]="张三"
# stu_obj1.age = 18 # stu_obj1.__dict__["age"]=18
# stu_obj1.gender = "male" # stu_obj1.__dict__["gender"]="male"
# stu_obj2.name = "李四"
# stu_obj2.age = 19
# stu_obj2.gender = "female"
# stu_obj3.name = "王五"
# stu_obj3.age = 23
# stu_obj3.gender = "male"
# 优化方案1:
# def init(obj,name,age,gender):
# obj.name = name
# obj.age = age
# obj.gender = gender
# init(stu_obj1, "张三" ,18,"male")
# init(stu_obj2, "李四" ,19,"female")
# init(stu_obj3, "王五" ,23,"male")
# print(stu_obj1.__dict__)
# print(stu_obj2.__dict__)
# print(stu_obj3.__dict__)
# 终极解决方案:
class Student:
school ="oldboy"
# 空对象,"张三",18,"male"
def __init__(obj, name, age, gender):
obj.name = name # 空对象.name = "张三"
obj.age = age # 空对象.age = 18
obj.gender = gender # 空对象.gender = "male"
# return None # 注意!!!:不能有返回值
def choose(self):
print('is choosing course')
# 调用类发生的事情
# 1、先造一个空对象(空对象的本质就是一个与类的内存空间相关联的、对象的内存空间)
# 2、触发类中的__init__函数的运行,会将(空对象"张三" ,18,"male")一起传给__init__函数,完成为对象初始化属性的操作
# 3、将初始化好属性的对象的内存地址赋值给等号左侧的变量名stu_obj1
stu_obj1=Student("张三" ,18,"male")
stu_obj2=Student("李四" ,19,"female")
stu_obj3=Student("王五" ,23,"male")
print(stu_obj1.__dict__)
print(stu_obj2.__dict__)
print(stu_obj3.__dict__)
四、 类与对象的属性操作
class Student:
school ="qinghua"
n=0
def __init__(obj, name, age, gender):
Student.n+=1
obj.name = name # 空对象.name = "张三"
obj.age = age # 空对象.age = 18
obj.gender = gender # 空对象.gender = "male"
def choose(self):
print('is choosing course')
stu_obj1=Student("张三" ,18,"male")
stu_obj2=Student("李四" ,19,"female")
stu_obj3=Student("王五" ,23,"male")
print(Student.n)
print(stu_obj1.n)
print(stu_obj2.n)
print(stu_obj3.n)
# 一 类与对象属性操作
# 1.对象的属性操作
# (1) 访问
# print(stu_obj1.name)
# print(stu_obj1.school)
# (2) 删除(只能清楚对象自己名称空间内的)
# del stu_obj1.name
# print(stu_obj1.__dict__)
# (3)新增与修改
# stu_obj1.x = 111
# print(stu_obj1.__dict__)
# stu_obj1.x = 222
# print(stu_obj1.x)
# 2.类的属性操作
# (1) 访问
# print(Student.school)
# print(Student.choose)
# (2) 删除(只能清楚类自己名称空间内的)
# del Student.school
# print(Student.__dict__)
# (3)新增与修改
# Student.xxx=111
# Student.xxx=222
# print(Student.__dict__)
# !!!总结
# 1、
# 对象.属性:先从对象自己的内存空间找,没有则去类中查找
# 类.属性:直接去类中查找
# stu_obj1.school = "xxx"
# print(stu_obj1.school)
# print(stu_obj2.school)
# print(stu_obj3.school)
# 2、类中定义的属性类可以使用,但其实是为对象准备的
# 类的数据属性是所有对象共享的
# print(Student.school,id(Student.school))
# Student.school="OLDBOY"
# print(stu_obj1.school,id(stu_obj1.school))
# print(stu_obj2.school,id(stu_obj2.school))
# print(stu_obj3.school,id(stu_obj3.school))
# 类的函数属性
print(Student.choose)
print(stu_obj1.choose)
print(stu_obj2.choose)
print(stu_obj3.choose)
五、 绑定方法
class Student:
school ="qinghua"
def __init__(self, name, age, gender):
self.name = name # 空对象.name = "张三"
self.age = age # 空对象.age = 18
self.gender = gender # 空对象.gender = "male"
def choose(self):
print('%s is choosing course' %self.name)
def tell_info(self):
print('<%s:%s:%s>' %(self.name,self.age,self.gender))
stu_obj1=Student("张三" ,18,"male")
stu_obj2=Student("李四" ,19,"female")
stu_obj3=Student("王五" ,23,"male")
stu_obj1.tell_info()
stu_obj2.tell_info()
stu_obj3.tell_info()
# 类中定义的函数类可以访问,但是类来访问的时候就是一个普通函数,必须按照普通函数的玩法来
# print(Student.choose)
# Student.choose(stu_obj1)
# print(stu_obj1.choose)
# print(stu_obj2.choose)
# print(stu_obj3.choose)
# 类中定义的函数其实是给对象准备的,对象来用,称之为调用绑定方法
# 绑定方法的特殊之处在于自动传参:会将调用者当作第一个参数自动传入
# stu_obj1.choose() # choose(stu_obj1)
# stu_obj2.choose() # choose(stu_obj2)
# stu_obj3.choose() # choose(stu_obj2)
# 在python3里统一了类与类型的概念
# l1=[1,2,3] # l1=list([1,2,3])
# print(type(l1))
# print(type(stu_obj1))
# l2=[11,22] # l1=list([1,2,3])
# l1.append(333)
# print(l1)
# l2.append(444)
# print(l2)
# list.append(l1,333)
# print(l1)
# list.append(l2,444)
# print(l2)
六、 三的特性之封装
"""
1 什么是封装
封装=》整合
2 为何要封装
为了让程序的整合程度更高,进而提升程序的解耦合程度
3 如何封装
3.1 把装到类或对象里的属性藏起来
(1)藏起来就是:把装进去的属性隐藏起来不让类外部访问到
(2)为何要将属性藏起来???
1、把数据属性藏器里的目的是:严格控制类外部使用者对属性的操作
不想让外部直接操作属性,通过开放接口的方式外部间接操作属性,
我们可以在接口之上附加任意控制逻辑,从而严格控制类外部使用者对属性的操作
2、把功能属性藏起来的目的是:为了隔离复杂度
(3)如何藏起来
在属性前加__开头,就会将该属性隐藏起来
注意:
(1) 这种不是真正意义上的隐藏,仅仅只是一种变形操作
(2) 该变形操作只在类定义阶段检查语法的时候变形一次,在此之后,新增的__开头的属性
都不会发生变形
(3) 该变形操作对外不内
"""
# 应用
class People:
def __init__(self,name,age,gender):
self.__name=name
self.age=age
self.gender=gender
def get_name(self):
print("名字:%s" %self.__name)
def set_name(self,val):
if type(val) is not str:
print("名字必须是str类型")
return
self.__name = val
def del_name(self):
print('不让删除')
p=People('egon',18,'male')
# p.__name=123123123
# print(p.name)
# p.get_name()
# p.set_name("EGON")
p.del_name()
# 示例
class Foo:
__x = 111 # _Foo__x = 111
def __init__(self, m, n):
self.__m = m # self._Foo__m = m
self.__n = n # self._Foo__n = n
def __f1(self): # _Foo__f1
print('from f1')
def f2(self): # self._Foo__m,self._Foo__n,self._Foo__x
print(self.__m,self.__n,self.__x)
# print(Foo.__x)
# print(Foo.__f1)
# print(Foo.__dict__)
# print(Foo._Foo__x)
# print(Foo._Foo__f1)
# obj1=Foo(666,777)
# print(obj1._Foo__x)
# print(obj1._Foo__f1)
# print(obj1.__dict__)
# print(obj1._Foo__m)
# print(obj1._Foo__n)
# Foo.__zzz=1111
# print(Foo.__dict__)
# print(Foo.__zzz)
# obj1=Foo(666,777)
# obj1.__yyy=222
# print(obj1.__dict__)
#
# obj1.f2()
七、 property装饰器
#1、property的基本使用
class People:
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
@property
def bmi(self):
return self.weight / (self.height ** 2)
p = People('wuchangwen', 1.8, 70)
# print(p.bmi())
# p.height=1.90
# print(p.bmi)
# 2、
# class People:
# def __init__(self,name):
# self.__name=name
#
# @property
# def name(self): # get
# return "名字:%s" %self.__name
#
# @name.setter
# def name(self,val): # set
# if type(val) is not str:
# print("名字必须是str类型")
# return
# self.__name = val
#
# @name.deleter
# def name(self): # del
# print('不让删除')
#
# p=People('wuchangwen')
# print(p.name)
# p.name=123
# del p.name
# print(p.name)
# 3、
class People:
def __init__(self,name):
self.__name=name
def get_name(self): # get
return "名字:%s" %self.__name
def set_name(self,val): # set
if type(val) is not str:
print("名字必须是str类型")
return
self.__name = val
def del_name(self): # del
print('不让删除')
name = property(get_name,set_name,del_name)
p=People('wuchangwen')
八、 三大特性之继承
"""
1 什么是继承?
继承是一种新建子类的方式,新建的类称之为子类,被继承的类称之为父类、基类、超类
继承的特点:子类会遗传父类的所有属性
2 为何要继承
类存在的意义是为了解决对象与对象之间的冗余问题
而继承的意义是为了解决类与类之间冗余问题
继承体现的一种耦合思想,于扩展性的增强无益
3 如何继承
语法:python支持单继承与多继承
单继承: 一个子类只能继承一个父类
多继承: 一个子类可以同时继承多个父类
ps:继承表达的是一个is-a的关系
单继承符合is-a的关系,可以让继承结构相对简单一点
而多继承不符合is-a的关系,盲目使用多继承会加大继承结构的复杂度,所以继承的正确打开方式是Mixins机制
"""
# class Parent1:
# pass
#
# class Parent2:
# pass
#
# class Sub1(Parent1):
# pass
#
# class Sub2(Parent1,Parent2):
# pass
#
#
# print(Sub1.__bases__)
# print(Sub2.__bases__)
#
#
# 案例1
# class Student:
# school = "qinghua"
#
# def __init__(self, name, age, gender,stu_id):
# self.name = name
# self.age = age
# self.gender = gender
#
# self.stu_id = stu_id
#
# def choose(self):
# print('is choosing course')
#
#
# class Teacher:
# school = "qinghua"
#
# def __init__(self, name, age, gender,level,salary):
# self.name = name
# self.age = age
# self.gender = gender
#
# self.level = level
# self.salary = salary
#
# def set_score(self, stu_obj, num):
# stu_obj.score = num
# print("老师<%s>给学生<%s>打了 %s 分" %(self.name,stu_obj.name,num))
#
# stu_obj1=Student("tom",18,'male',3536)
# tea_obj1=Teacher("wuchangwen",18,'male',10,3000)
#
# # tea_obj1.set_score(stu_obj1,60)
# # print(stu_obj1.score)
# 如何在子类派生的新方法中重父类的功能
# 方案一:指名道姓地调用某一个类的函数,不依赖于继承
class People:
school = "qinghua"
# 空对象,"tom",18,'male'
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
class Student(People):
# 空对象,"tom",18,'male',3536
def __init__(self,name,age,gender,stu_id):
People.__init__(self,name,age,gender)
self.stu_id=stu_id
def choose(self):
print('is choosing course')
class Teacher(People):
def __init__(self, name, age, gender,level,salary):
People.__init__(self,name,age,gender)
self.level = level
self.salary = salary
def set_score(self, stu_obj, num):
stu_obj.score = num
print("老师<%s>给学生<%s>打了 %s 分" %(self.name,stu_obj.name,num))
stu_obj1=Student("tom",18,'male',3536)
tea_obj1=Teacher("egon",18,'male',10,3000)
print(stu_obj1.__dict__)
print(tea_obj1.__dict__)
九、 属性的查找
# 在单继承背景下的属性查找:
# 1、obj.x
# 对象=》对象的类=》父类=》父父类。。。
# 2、类名.x
# 当前类=》父类=》父父类。。。
# 示例1:
# class Foo:
# def f1(self):
# print("Foo.f1")
#
# def f2(self):
# print('Foo.f2')
# self.f1() # obj.f1()
#
# class Sub(Foo):
# def f1(self):
# print("Sub.f1")
#
# obj=Sub()
# obj.f2()
# """
# Foo.f2
# Sub.f1
# """
# 示例2
class Foo:
def __f1(self): # _Foo__f1
print("Foo.f1")
def f2(self):
print('Foo.f2')
self.__f1() # self._Foo__f1
class Sub(Foo):
def __f1(self): # _Sub__f1
print("Sub.f1")
obj=Sub()
obj.f2()
"""
Foo.f2
Sub.f1
"""
十、 多继承
#coding:utf-8
# 在python中,针对每一个类python解释器都会基于c3算法为其计算出一个MRO列表
# ps: 在python中有新式类与经典类之分
# 新式类:但凡是继承了object类的子类,以及该子类的子子孙孙类都是新式类
# 经典类:没有继承object类的子类,以及该子类的子子孙孙类都是经典类
# 注意:在python3中,如果一个子类没有继承任何类,那么python会让其默认继承object类
# 所以说,只有在python2中才存在经典类
# class Foo(object):
# pass
#
# class Bar(Foo):
# pass
#
# class A(Bar):
# pass
#
# # print(A.mro())
# # obj=A()
# # obj.x
#
# print(Bar.mro())
# b=Bar()
# # b.x
# !!! 重要结论:由谁引发的属性查找,就参照谁的MRO列表
# class E:
# def test(self):
# print('from E')
#
#
# class F:
# def test(self):
# print('from F')
#
#
# class B(E):
# def test(self):
# print('from B')
#
#
# class C(F):
# def test(self):
# print('from C')
#
#
# class D:
# def test(self):
# print('from D')
#
#
# class A(B, C, D):
# # def test(self):
# # print('from A')
# pass
# print(A.mro())
'''
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]
'''
# obj = A()
# obj.test()
# 菱形继承:一个子类继承的多个父类汇聚到一个非object类
# 新式类与经典类关于属性的查找不一样
# (1)新式类:广度优先
# (2)经典类:深度优先
class G: # 在python2中,未继承object的类及其子类,都是经典类
# def test(self):
# print('from G')
pass
class E(G):
# def test(self):
# print('from E')
pass
class F(G):
def test(self):
print('from F')
class B(E):
# def test(self):
# print('from B')
pass
class C(F):
def test(self):
print('from C')
class D(G):
def test(self):
print('from D')
# print(D.mro())
class A(B,C,D):
# def test(self):
# print('from A')
pass
obj = A()
# print(A.mro())
obj.test()
十一、 supper方法
# 如何在子类派生的新方法中重父类的功能
# 方案一:指名道姓地调用某一个类的函数,不依赖于继承
# 方案二:super()会返回一个特殊的对象,super().x该对象会参照当前类的mro列表去父类里找,严格依赖继承
class People:
school = "oldboy"
# 空对象,"tom",18,'male'
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def tell_info(self):
print("名字:%s" %self.name)
print("年龄:%s" %self.age)
print("性别:%s" %self.gender)
class Student(People):
# 空对象,"tom",18,'male',3536
def __init__(self,name,age,gender,stu_id):
# People.__init__(self,name,age,gender)
# super(Student,self).__init__(name,age,gender) # 在python2中
super().__init__(name,age,gender) # 在python2中
self.stu_id=stu_id
def choose(self):
print('is choosing course')
def tell_info(self):
print("学号:%s" %self.stu_id)
super().tell_info()
class Teacher(People):
def __init__(self, name, age, gender,level,salary):
# People.__init__(self,name,age,gender)
super().__init__(name,age,gender) # 在python2中
self.level = level
self.salary = salary
def set_score(self, stu_obj, num):
stu_obj.score = num
print("老师<%s>给学生<%s>打了 %s 分" %(self.name,stu_obj.name,num))
stu_obj1=Student("tom",18,'male',3536)
tea_obj1=Teacher("egon",18,'male',10,3000)
# print(stu_obj1.__dict__)
# print(tea_obj1.__dict__)
# stu_obj1.tell_info()
# tea_obj1.tell_info()
class A:
def test(self):
super().test() # 参照属性发起者的mro,去父类里找属性
class B:
def test(self):
print('from B')
class C(A,B):
pass
# obj=C()
# obj.test()
# print(C.mro())
obj=A()
print(A.mro())
obj.test()
作者:吴常文
出处:https://blog.csdn.net/qq_41405475
本文版权归作者和CSDN共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。