面向对象基础
面向对象编程介绍
'''
面向过程的编程思想
核心过程二字,过程指的是解决问题的步骤,即先干什么再干什么后干什么
基于该思想编写程序就好比在设计一条流水线,是一种机械式的思维方式
优点:复杂的问题流程化进而简单化
缺点:可扩展性差
面向对象的编程思想
核心是对象二字,对象是特征与技能的结合体
基于该思想编写程序(脑子始终想的是对象二字)就好比在创造一个世界,世界是由一个个对象组成,在上帝眼里任何存在的事物都是对象,任何不存在的事物也都可以造出来,是一种上帝式的思维方式
优点: 可扩展性强
缺点: 编程的复杂度要高与面向过程
类:
对象是特征与技能的结合体,而类则是一系列对象相同的特征与技能的结合体
强调:
1.对象是具体存在的事物,而类则一个抽象的概念
2.站在不同的角度总结出的类与对象是不同的
在现实世界中:先有一个个具体存在的对象,然后随着人类文明的发展才总结出类的概念
在程序中: 先定义类,后调用类来产生对象
站在老男孩选课系统的角度
总结出现实世界中的老男孩学生对象:
学生对象1
特征
school='oldboy'
name='李铁蛋'
age=18
sex='male'
技能
选课
学生对象2
特征
school='oldboy'
name='赵钢弹'
age=38
sex='female'
技能
选课
学生对象3
特征
school='oldboy'
name='刘银弹'
age=28
sex='male'
技能
选课
老师对象1
特征
school='oldboy'
name='Egon'
age=18
sex='male'
level=10
技能
打分
总结现实世界中的老男孩学生类
相同的特征
school='oldboy'
相同的技能
选课
在程序中....
'''
类的使用
'''
站在老男孩选课系统的角度
总结出现实世界中的老男孩学生对象:
学生对象1
特征
school='oldboy'
name='李铁蛋'
age=18
sex='male'
技能
选课
学生对象2
特征
school='oldboy'
name='赵钢弹'
age=38
sex='female'
技能
选课
学生对象3
特征
school='oldboy'
name='刘银弹'
age=28
sex='male'
技能
选课
总结现实世界中的老男孩学生类
相同的特征
school='oldboy'
相同的技能
选课
'''
# 在程序中
# 1. 先定义类
class OldboyStudent:
#相同的特征
school = 'oldboy'
#相同的技能
def choose_course(self):
print('choosing course')
# print('===>>>')
# 类是一系列对象相同的特征(变量)与技能(函数)的结合体,即类体中最常见的就是变量与函数的定义
# 但其实类体中是可以存在任意python代码的
# 类体代码会在类定义阶段立即执行,会产生一个类名称空间,用来将类体代码执行过程中产生的名字都丢进去,查看方式如下
print(OldboyStudent.__dict__) # 查看类的名称空间
print(OldboyStudent.school) # print(OldboyStudent.__dict__['school'])
print(OldboyStudent.choose_course)
OldboyStudent.school='OLDBOY' # OldboyStudent.__dict__['school']='OLDBOY'
OldboyStudent.country='China' # OldboyStudent.__dict__['country']='China'
del OldboyStudent.country # del OldboyStudent.__dict__['country']
print(OldboyStudent.__dict__)
OldboyStudent.choose_course(123123)
# 总结:
# 1. 类本质就是一个名称空间,或者说是一个用来存放变量与函数的容器
# 2. 类的用途之一就是当做名称空间从其内部取出名字来使用
# 3. 类的用途之二是调用类来产生对象
#2. 后调用类来产生对象
对象的使用
'''
学生对象1
特征
school='oldboy'
name='李铁蛋'
age=18
sex='male'
技能
选课
学生对象2
特征
school='oldboy'
name='赵钢弹'
age=38
sex='female'
技能
选课
学生对象3
特征
school='oldboy'
name='刘银弹'
age=28
sex='male'
技能
选课
'''
class OldboyStudent:
#相同的特征
school = 'oldboy'
#相同的技能
def choose_course(self):
print('choosing course')
# 2. 后调用类来产生对象:
# 调用类的过程称之为类的实例化,调用类的返回值称之为类的一个对象/实例
# 调用类发生了?
# 1. 会产生一个对象,然后返回
stu1=OldboyStudent()
stu2=OldboyStudent()
stu3=OldboyStudent()
# print(stu1.__dict__)
# print(stu2.__dict__)
# print(stu3.__dict__)
# 为对象定制自己独有的特征
'''
# name='李铁蛋'
# age=18
# sex='male'
stu1.name='李铁蛋'
stu1.age=18
stu1.sex='male'
print(stu1.__dict__)
# name='赵钢弹'
# age=38
# sex='female'
stu2.name='赵钢弹'
stu2.age=38
stu2.sex='female'
print(stu2.__dict__)
# name='刘银弹'
# age=28
# sex='male'
stu3.name='刘银弹'
stu3.age=28
stu3.sex='male'
print(stu3.__dict__)
'''
# 为对象定制自己独有的特征,简化方案一:
'''
def init(obj,name,age,sex):
obj.name = name
obj.age = age
obj.sex = sex
# stu1.name='李铁蛋'
# stu1.age=18
# stu1.sex='male'
init(stu1,'李铁蛋',18,'male')
# stu2.name='赵钢弹'
# stu2.age=38
# stu2.sex='female'
init(stu2,'赵钢弹',38,'female')
# stu3.name='刘银弹'
# stu3.age=28
# stu3.sex='male'
init(stu3,'刘银弹',28,'male')
print(stu1.__dict__)
print(stu2.__dict__)
print(stu3.__dict__)
'''
# 为对象定制自己独有的特征,简化方案二:
class OldboyStudent:
#相同的特征
school = 'oldboy'
# stu1,'李铁蛋',18,'male'
def __init__(obj, name, age, sex):
obj.name = name #stu1.name='李铁蛋'
obj.age = age #stu1.age=18
obj.sex = sex #stu1.sex='male'
#相同的技能
def choose_course(self):
print('choosing course')
# 调用类发生了
# 1. 先产生一个空对象stu1,然后返回
# 2. 触发类中函数__init__的执行,将对象连同调用类括号内指定的参数一同传入__init__(stu1,'李铁蛋',18,'male')
stu1=OldboyStudent('李铁蛋',18,'male') #__init__(stu1,'李铁蛋',18,'male')
stu2=OldboyStudent('赵钢弹',38,'female') #__init__(stu2,'赵钢弹',38,'female')
stu3=OldboyStudent('刘银弹',28,'male') #__init__(stu3,'刘银弹',28,'male')
# print(stu1.__dict__)
# print(stu2.__dict__)
# print(stu3.__dict__)
# 总结__init__的功能: 是在实例化时就为对象初始自己独有的特征
# 注意:不能有返回值
# stu1.xxx=111
# print(stu1.__dict__)
属性查找
xxx=33333
class OldboyStudent:
school = 'oldboy'
# xxx=2222
yyy=333
count=0
def __init__(obj, name, age, sex):
# print(OldboyStudent.yyy)
# print(obj.yyy)
OldboyStudent.count+=1 #实现对对象的引用计数
obj.name = name #stu1.name='李铁蛋'
obj.age = age #stu1.age=18
obj.sex = sex #stu1.sex='male'
def choose_course(self):
print('choosing course')
# 1. 属性查找顺序
stu1=OldboyStudent('李铁蛋',18,'male')
print(stu1.__dict__)
print(OldboyStudent.__dict__)
stu1.xxx=111
print(stu1.__dict__)
# 先从对象自己的名称空间找,没有则去所属的类中找
print(stu1.xxx)
# 2.
stu1=OldboyStudent('李铁蛋',18,'male')
stu2=OldboyStudent('赵钢弹',38,'female')
stu3=OldboyStudent('刘银弹',28,'male')
# print(stu1.count)
# print(stu2.count)
# print(stu3.count)
# print(OldboyStudent.count)
# 类中定义的变量是所有对象共享的,对象可以来用,类也可以来使用,类一旦改变自己的数据属性的值,所有的对象都能感知到
# print(id(stu1.school))
# print(id(stu2.school))
# print(id(stu3.school))
# print(id(OldboyStudent.school))
stu1.school=123 #只改变对象中的变量不会影响类中的变量值
# OldboyStudent.school='OLDBOY' #改变类会影响到所有对象中的值
# print(stu1.__dict__)
# print(stu2.__dict__)
# print(stu3.__dict__)
# print(OldboyStudent.__dict__)
#
# print(OldboyStudent.school)
# print(stu1.school)
# print(stu2.school)
# print(stu3.school)
# print(id(stu1.choose_course))
# print(id(stu2.choose_course))
# print(id(stu3.choose_course))
绑定方法
# 类中定义的变量是类的数据属性,类可以用,对象也可以用,大家都指向同一个内存地址,类变量值一旦改变所有对象都跟着变
# 类中定义的函数是类的函数属性,类可以用,类来调用就是一个普通的函数,但其实类中定义的函数是给对象用的,而且是绑定给对象用的
# 绑定???
class OldboyStudent:
school = 'oldboy'
def __init__(self, name, age, sex):
self.name = name #stu1.name='李铁蛋'
self.age = age #stu1.age=18
self.sex = sex #stu1.sex='male'
def choose_course(self,x): #self=stu1
print('%s choosing course' %self.name)
stu1=OldboyStudent('李铁蛋',18,'male')
stu2=OldboyStudent('赵钢弹',38,'female')
stu3=OldboyStudent('刘银弹',28,'male')
# 1. 类的函数: 该传几个参数就传几个
# print(OldboyStudent.__init__)
# print(OldboyStudent.choose_course)
# OldboyStudent.choose_course(stu1)
# 2. 绑定方法,指向类的函数: 特殊之处是绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数自动传入
# print(stu1.choose_course)
# print(stu2.choose_course)
# print(stu3.choose_course)
# stu1.choose_course(123) # OldboyStudent.choose_course(stu1,123)
# stu2.choose_course(123)
# stu3.choose_course(123)
# stu1.choose_course() #这样会报错,因为没有给x传参
一切皆对象
# 在python3中统一了类与类型的概念
class Foo:
pass
# print(Foo)
# obj=Foo()
# print(type(obj))
# print(int)
# age=10 #age=int(10)
# print(type(age))
l1=[1,2,3] #l1=list([1,2,3])
# print(type(l1))
# l1.append(4)
# print(l1)
l1.append(4) # 相当于 list.append(l1,4)
print(l1)
l2=['a','b','c'] # l2=list(['a','b','c'])
l2.append('d')
三大特性之一:继承
继承介绍
'''
1 什么是继承
继承一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类基类超类
python中继承的特点:
1. 子类可以遗传/重用父类的属性
2. python中一个子类可以同时继承多个父类
3. 在继承背景下去说,python中的类分为两种:新式类,经典类
新式类: 但凡继承了object的类Foo,以及该类的子类...都是新式类
在python3中一个类即便是没有显式地继承任何类,默认就会继承object
即python3中所有的类都是新式类
经典类:没有继承object的类,以及该类的子类...都是经典类
在python2中才区分新式类与经典类,
在python2中一个类如果没有显式地继承任何类,也不会继承object
2 为何要用继承
减少类与类之间代码冗余
3 如何用继承
'''
class Parent1(object): # 父类
pass
class Parent2(object): # 父类
pass
class Sub1(Parent1): # 子类,继承父类
pass
class Sub2(Parent1,Parent2): # 子类,多继承父类
pass
print(Parent1.__bases__) #(<class 'object'>,)
print(Parent2.__bases__) #(<class 'object'>,)
print(Sub1.__bases__) #(<class '__main__.Parent1'>,)
print(Sub2.__bases__) #(<class '__main__.Parent1'>, <class '__main__.Parent2'>)
class Parent1(object):
xxx=333
class Sub1(Parent1):
# xxx=222 # 333
pass
obj=Sub1()
# obj.xxx=111 # 222
print(obj.xxx) # 111
# 问题:
# 1 子类如何重用父类的属性
# 2 在继承背景下,属性查找的优先级
# 3 新式类与经典类在属性查找上的区别
利用继承来解决类与类之间代码冗余问题
class OldboyPeople: # 父类(=子类1+子类2)
school = 'Oldboy'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople): # 子类1
# def __init__(self, name, age, sex, score=0):
# self.name = name
# self.age = age
# self.sex = sex
# self.score = score
def choose_course(self):
print('%s choosing course' % self.name)
class OldboyTeacher(OldboyPeople): # 子类2
# def __init__(self,name,age,sex,level):
# self.name=name
# self.age=age
# self.sex=sex
# self.level=level
def score(self,stu,num):
stu.score=num
stu1=OldboyStudent('刘二蛋',38,'male')
print(stu1.__dict__)
tea1=OldboyTeacher('egon',18,'male')
print(tea1.__dict__)
在子类派生的新方法中重用父类功能的方式一
# 在子类派生出的新方法中重用父类功能的方式一:
# 指名道姓地引用某一个类中的函数
# 总结:
# 1. 与继承无关
# 2. 访问是类的函数,没有自动传值的效果
class OldboyPeople:
school = 'Oldboy'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex, score=0):
OldboyPeople.__init__(self,name,age,sex)
self.score = score
def choose_course(self):
print('%s choosing course' % self.name)
class OldboyTeacher(OldboyPeople):
def __init__(self,name,age,sex,level):
OldboyPeople.__init__(self,name,age,sex)
self.level=level
def score(self,stu,num):
stu.score=num
stu1=OldboyStudent('刘二蛋',38,'male')
print(stu1.__dict__)
tea1=OldboyTeacher('egon',18,'male',10)
print(tea1.__dict__)
在单继承背景下的属性查找
# 在单继承背景下属性的查找优先级:对象->对象的类->父类->父类.....
class Foo:
# xxx=444
pass
class Bar1(Foo):
# xxx=333
pass
class Bar2(Bar1):
# xxx=222
pass
obj=Bar2()
# obj.xxx=111
print(obj.xxx)
class Foo:
def f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.f1() #obj.f1()
class Bar(Foo):
def f1(self):
print('Bar.f1')
obj=Bar()
obj.f2()
'''
Foo.f2
Bar.f1
'''
在多继承背景下的属性查找
# 在多继承背景下属性的查找优先级:
# 如果一个子类继承多个分支(多个分支没有共同继承一个非object的类)
# 此时属性的查找优先级是:对象->对象的类->按照从左往右的顺序一个分支一个分支的找下去
# 第四层:
class G:
# x = 'G'
pass
# 第三层
class E(G):
# x = 'E'
pass
class F:
# x = 'F'
pass
# 第二层
class B(E):
# x = 'B'
pass
class C(F):
# x = 'C'
pass
class D:
# x = 'D'
pass
# 第一层
class A(B, C, D):
# x = 'A'
pass
obj = A()
# obj.x = 111
print(obj.x)
# 菱形继承问题:
# 新式类 : 广度优先查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类
# 经典类 : 深度优先查找,从左往右一个分支一个分支的查找,在第一个分支就查找顶级类
# 第四层:
class G(object):
# x = 'G'
pass
# 第三层
class E(G):
# x = 'E'
pass
class F(G):
# x = 'F'
pass
# 第二层
class B(E):
# x = 'B'
pass
class C(F):
# x = 'C'
pass
class D(G):
# x = 'D'
pass
# 第一层
class A(B, C, D):
# x = 'A'
pass
obj=A()
# obj.x=111
print(obj.x)
#新式类(广度优先): obj->A->B->E->C-F->D->G->object
#经典类(深度优先): obj->A->B->E->G->C-F->D
# python专门为新式类内置了一个mro的方法,用来查看c3算法的计算结果,结果是??
print(A.mro())
在子类派生的新方法中重用父类功能的方式二
# 在子类派生出的新方法中重用父类功能的方式二:super()必须在类中用
# 在python2中:super(自己的类名,自己的对象)
# 在python3中:super()
# 调用该函数会得到一个特殊的对象,该对象专门用来访问父类中的属性,!!!完全参照mro列表!!!!
# 总结:
# 1. 严格依赖继承的mro列表
# 2. 访问是绑定方法,有自动传值的效果
class OldboyPeople:
school = 'Oldboy'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex, score=0):
super(OldboyStudent,self).__init__(name,age,sex)
self.score = score
def choose_course(self):
print('%s choosing course' % self.name)
class OldboyTeacher(OldboyPeople):
def __init__(self,name,age,sex,level):
super().__init__(name,age,sex)
self.level=level
def score(self,stu,num):
stu.score=num
stu1=OldboyStudent('刘二蛋',38,'male')
print(stu1.__dict__)
tea1=OldboyTeacher('egon',18,'male',10)
print(tea1.__dict__)
class A:
def f1(self):
print('A.f1')
super().f2()
class B:
def f2(self):
print('B.f2')
class C(A,B):
def f2(self):
print('C.f2')
obj=C()
print(C.mro())
obj.f1() # 结果要根据mro中的值来判断
'''
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
A.f1
B.f2
'''
继承总结
1. 什么是继承
继承是一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类/基类/超类
继承有3个特点:
1. 子类可以遗传/重用父类的属性(解决类与类之间代码冗余的问题)
2. 在python中一个子类可以同时继承多个父类
3. 在继承的背景下,类分为两种:新式类,经典类
新式类:但凡继承object类的子类,以及该子类的子子孙孙都是新式类
在python3中一个类即便是没有显式地继承任何类,默认就继承object类,
即在python3中所有类都是新式类
经典类:没有继承object类的子类,以及该子类的子子孙孙都是经典类
强调:只有在python2中才有经典类
在python2中如果一个类没有显式地继承任何类,并不会自动继承object类
2. 为何要用继承:减少类与类之间的代码冗余
3. 如何继承
class Foo:
pass
class Bar(Foo):
pass
#obj=Bar()
#obj.x
Bar.x
4. 属性查找
在没有出现菱形继承的情况下,属性的查找是按照从左往右的顺序一个分支一个分支的找下去
在出现菱形继承(一个子类继承的多个分支最终汇聚到一个非object类)的情况下,
新式类:广度优先查找,按照从左往右的顺序一个分支一个分支的找下去,在最后一个分支才去查找顶级类
经典类:深度优先查找,按照从左往右的顺序一个分支一个分支的找下去,在第一个分支就查找顶级类
5. 派生
在子类中定义自己的属性,如果与父类的属性重名,那以自己的为准.
在子类派生的新方法中重用父类的功能:
方式一:指名道姓地调用某一个类的函数
特点:
1. 与继承无关
2. 没有自动传值的效果
方式二:super()得到一个特殊的对象,该对象专门用来引用父类的属性
特点:
1. 严格依赖继承,完全参照mro
2. 有自动传值的效果
组合
'''
1. 什么是组合
组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象
class Foo:
pass
class Bar:
pass
obj=Foo()
obj.attr=Bar()
obj.xxx
obj.attr.yyy
2. 为何要用组合
通过为某一个对象添加属性(属性的值是另外一个类的对象)的方式,可以间接地将两个类关联/整合/组合到一起
从而减少类与类之间代码冗余
class Foo1:
pass
class Foo2:
pass
class Foo3:
pass
class Bar:
pass
obj_from_bar=Bar()
obj1=Foo1()
obj2=Foo2()
obj3=Foo3()
obj1.attr1=obj_from_bar
obj2.attr2=obj_from_bar
obj3.attr3=obj_from_bar
3. 如何用组合
class OldboyPeople:
school = 'Oldboy'
def __init__(self,name,age,sex,):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex,score=0):
OldboyPeople.__init__(self,name,age,sex)
self.score = score
def choose_course(self):
print('%s choosing course' % self.name)
class OldboyTeacher(OldboyPeople):
def __init__(self,name,age,sex,level):
OldboyPeople.__init__(self,name,age,sex)
self.level=level
def score(self,stu,num):
stu.score=num
class Course:
def __init__(self,c_name,c_price,c_period):
self.c_name = c_name
self.c_price = c_price
self.c_period = c_period
def tell_info(self):
print('<课程名:%s 价钱:%s 周期:%s>' %(self.c_name,self.c_price,self.c_period))
# 创建课程对象
python=Course('python全栈开发',1900,'5mons')
linux=Course('linux架构师',900,'3mons')
stu1=OldboyStudent('刘二蛋',38,'male')
stu1.course=python
# print(stu1.__dict__)
stu1.course.tell_info()
tea1=OldboyTeacher('egon',18,'male',10)
tea1.course=python
# print(tea1.__dict__)
tea1.course.tell_info()
'''
class OldboyPeople:
school = 'Oldboy'
def __init__(self,name,age,sex,):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex,score=0):
OldboyPeople.__init__(self,name,age,sex)
self.score = score
self.courses=[]
def choose_course(self):
print('%s choosing course' % self.name)
def tell_all_course(self):
print(('学生[%s]选修的课程如下' %self.name).center(50,'='))
for obj in self.courses:
obj.tell_info()
print('='*60)
class OldboyTeacher(OldboyPeople):
def __init__(self,name,age,sex,level):
OldboyPeople.__init__(self,name,age,sex)
self.level=level
self.courses=[]
def score(self,stu,num):
stu.score=num
def tell_all_course(self):
print(('老师[%s]教授的课程如下' %self.name).center(50,'*'))
for obj in self.courses:
obj.tell_info()
print('*'*70)
class Course:
def __init__(self,c_name,c_price,c_period):
self.c_name = c_name
self.c_price = c_price
self.c_period = c_period
def tell_info(self):
print('<课程名:%s 价钱:%s 周期:%s>' %(self.c_name,self.c_price,self.c_period))
# 创建课程对象
python=Course('python全栈开发',1900,'5mons')
linux=Course('linux架构师',900,'3mons')
stu1=OldboyStudent('刘二蛋',38,'male')
stu1.courses.append(python)
stu1.courses.append(linux)
# print(stu1.courses)
stu1.tell_all_course()
tea1=OldboyTeacher('egon',18,'male',10)
tea1.courses.append(python)
# print(tea1.courses)
tea1.tell_all_course()
三大特性之二:多态
多态与多态性
'''
1. 什么是多态
多态指的是同一种/类事物的不同形态
2. 为何要用多态
多态性:在多态的背景下,可以在不用考虑对象具体类型的前提下而直接使用对象
多态性的精髓:统一
3. 如何用多态
'''
'''
class Animal:
def speak(self):
pass
class People(Animal):
def shuo(self):
print('say hello')
class Dog(Animal):
def jiao(self):
print('汪汪汪')
class Pig(Animal):
def chang(self):
print('哼哼哼')
obj1=People()
obj2=Dog()
obj3=Pig()
# obj1.speak()
# obj2.speak()
# obj3.speak()
def speak(animal):
animal.speak()
speak(obj1)
speak(obj2)
speak(obj3)
s1='hello'
l1=[1,2,3]
t1=(1,2)
# changdu(s1)
# size(l1)
# kuangdu(t1)
print(len(s1)) #s1.__len__()
print(len(l1)) #l1.__len__()
print(len(t1)) #t1.__len__()
'''
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def speak(self):
pass
@abc.abstractmethod
def run(self):
pass
# Animal() # 父类只是用来建立规范的,不能用来实例化的,更无需实现内部的方法
class People(Animal):
def speak(self):
print('say hello')
def run(self):
pass
class Dog(Animal):
def speak(self):
print('汪汪汪')
def run(self):
pass
class Pig(Animal):
def speak(self):
print('哼哼哼')
def run(self):
pass
obj1=People()
obj2=Dog()
obj3=Pig()
# python崇尚鸭子类型
class Disk:
def read(self):
print('Disk read')
def write(self):
print('Disk write')
class Memory:
def read(self):
print('Mem read')
def write(self):
print('Mem write')
class Cpu:
def read(self):
print('Cpu read')
def write(self):
print('Cpu write')
obj1=Disk()
obj2=Memory()
obj3=Cpu()
obj1.read()
obj2.read()
obj3.read()
三大特性之二:封装
封装
'''
1. 什么是封装
装:往容器/名称空间里存入名字
封:代表将存放于名称空间中的名字给藏起来,这种隐藏对外不对内
2. 为何要封装
封数据属性:???
封函数属性:???
3. 如何封装
在类内定义的属性前加__开头(没有__结果)
总结:
1. __开头的属性实现的隐藏仅仅只是一种语法意义上的变形,并不会真的限制类外部的访问
2. 该变形操作只在类定义阶段检测语法时发生一次,类定义阶段之后新增的__开头的属性并不会变形
3. 如果父类不想让子类覆盖自己的属性,可以在属性前加__开头
'''
class Foo:
__x=111 # _Foo__x
__y=222 # _Foo__y
def __init__(self,name,age):
self.__name=name
self.__age=age
def __func(self): #_Foo__func
print('func')
def get_info(self):
print(self.__name,self.__age,self.__x) #print(self._Foo__name,self._Foo__age,self._Foo__x)
# print(Foo.__x)
# print(Foo.__func)
# print(Foo.__dict__)
# print(Foo._Foo__x)
# print(Foo._Foo__y)
# Foo.__z=333
# print(Foo.__dict__)
# print(Foo.__z)
obj=Foo('egon',18)
# print(obj.__dict__)
# print(obj.__name)
# print(obj.__age)
# obj.get_info()
obj.__sex='male'
# print(obj.__dict__)
# print(obj.__sex)
# obj.get_info()
# 1. __开头的属性到底如何实现的隐藏?
# 2. 如何实现的对外隐藏,对内不隐藏
class Foo:
def __f1(self): #_Foo__f1
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.__f1() #obj._Foo__f1()
class Bar(Foo):
def __f1(self): # _Bar__f1 (与上面的__f1就不一样了)
print('Bar.f1')
obj=Bar()
# obj.f2()
'''
Foo.f2
Foo.f1
'''
# 封装数据属性:将数据属性隐藏起来,类外就无法直接操作属性,需要类内开辟一个接口来外部的使用可以间接地操作属性,可以在接口内定义任意的控制逻辑,
# 从而严格控制使用对属性的操作
class People:
def __init__(self,name,age):
self.__name=name
self.__age=age
def tell_info(self): # 为了让外部能够访问到(这种访问是间接的,是提供给外部的)
print('<name:%s age:%s>' %(self.__name,self.__age))
def set_info(self,name,age): # 为了让外部改数据(同上)
if type(name) is not str:
print('名字必须是str类型傻叉')
return
if type(age) is not int:
print('年龄必须是int类型傻叉')
return
self.__name=name
self.__age=age
obj=People('egon',18)
# obj.tell_info()
# obj.set_info('EGON',19)
# obj.set_info(123,19)
obj.set_info('EGON','18')
obj.tell_info()
# 封装函数属性:隔离复杂度
class ATM:
def __card(self):
print('插卡')
def __auth(self):
print('用户认证')
def __input(self):
print('输入取款金额')
def __print_bill(self):
print('打印账单')
def __take_money(self):
print('取款')
def withdraw(self):
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money()
a=ATM()
a.withdraw()
property
# property装饰器是用来将类内的函数属性伪装成数据属性
class People:
def __init__(self,name,weight,height):
self.name=name
self.weight=weight
self.height=height
@property
def bmi(self):
return self.weight / (self.height ** 2)
obj=People('egon',80,1.83)
obj.height=1.85
obj.weight=75
print(obj.bmi()) # 没用装饰器之前
print(obj.bmi) # 用过装饰器之后可以直接将bmi当做数据来看待
# 了解....
class People:
def __init__(self,name):
self.__name=name
@property
def name(self):
return '<名字:%s>' %self.__name
@name.setter #为对象修改属性,但在此之前要用property修饰过
def name(self,obj):
if type(obj) is not str:
print('name必须为str类型')
return
self.__name=obj
@name.deleter #删除属性操作
def name(self):
# print('不让删')
del self.__name
obj=People('egon')
# print(obj.name)
# obj.name='EGON'
# obj.name=123
# print(obj.name)
# del obj.name
# print(obj.__dict__)
# 另外一种写法
class People:
def __init__(self,name):
self.__name=name
def get_name(self):
return '<名字:%s>' %self.__name
def set_name(self,obj):
if type(obj) is not str:
print('name必须为str类型')
return
self.__name=obj
def del_name(self):
# print('不让删')
del self.__name
#不推荐这种写法,建议用上面的写法
name=property(get_name,set_name,del_name)
obj=People('egon')
print(obj.name)
obj.name='EGON'
obj.name=123
print(obj.name)
del obj.name
print(obj.__dict__)
绑定方法与非绑定方法
# 一: 绑定方法:绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数传入
# 1. 绑定给对象的方法: 类中定义的函数默认就是绑定给对象的
# 2. 绑定给类的方法: 为类中定义的函数加上一个装饰器classmethod
# 二: 非绑定方法: 既不与类绑定,又不与对象绑定,意味着对象和类都可以来调用,无论谁来调用都是一个普通的函数,没有自动传值的效果
class Foo:
def f1(self):
print(self)
@classmethod
def f2(cls):
print(cls)
@staticmethod
def f3(x,y):
print('f3',x+y)
obj=Foo()
print(obj.f1)
obj.f1()
print(Foo.f2)
Foo.f2()
print(obj.f2)
obj.f2()
print(Foo.f3)
print(obj.f3)
Foo.f3(1,2)
obj.f3(3,4)
# 应用
import settings
class MySql:
def __init__(self, ip, port):
self.id = self.create_id()
self.ip = ip
self.port = port
def tell_info(self):
print('<id:%s ip:%s port:%s>' % (self.id, self.ip, self.port))
@classmethod #为类提供额外的实列化方式
def from_conf(cls):
return cls(settings.IP, settings.PORT)
@staticmethod #既不需要传类也不需要传对象
def create_id():
import uuid
return uuid.uuid4()
# obj1=MySql('1.1.1.1',3306)
# obj1.tell_info()
obj2 = MySql.from_conf()
obj2.tell_info()
面向对象串讲
'''
1 类与对象
对象是特征与技能的结合体,而类则是一些列对象相同特征与技能的结合
对象本质是一个容器/名称空间:用来存放对象特有的属性
类的本质也是一个容器/名称空间:用来存放对象相同的属性
类有两种用途:
1. 当容器去用
类的数据属性
类的函数属性
2. 调用类的过程称为实例化,结果就是对象
实例化时方式两件事:
1. 先产生一个空对象
2. 触发__init__(空对象,arg1,arg2,...)
2 继承与派生
1. 什么是继承
继承是一种新建类的方式,新建的类称之为子类/派生类,被继承类称之为父类/超类/基类
继承描述的是一种遗传的关系,特点:
1. 子类可以遗传/重用父类的属性(减少代码冗余)
2. 一个子类可以同时继承多个父类
3. 在继承的背景下,类分为新式类与经典类
子类如何重用父类属性?
在继承背景下属性的查找顺序???
新式类vs经典类
2. 为何要用继承
解决类与类之间代码冗余的问题
3. 如何继承
class Foo:
pass
class Bar(Foo):
x=1
obj=Bar()
4. 在子类派生新方法中重用父类功能的两种方式:
方式一:指名道姓地访问某一个类的函数
特点:
1. 与继承无关
2. 没有自动传值的效果
方式二:super(自己的类名,self)会得到一个特殊的对象,该对象专门用来访问"父类"中的属性,完全参照mro列表
特点:
1. 严格依赖继承,完全参照mro列表
2. 有自动传值的效果
3 组合
1. 什么是组合
组合指的是一个对象拥有某一个属性,该属性的值是来自于另外一个类的对象
class OldboyStudent:
pass
class OldboyTeacher:
pass
class Course:
pass
stu=OLdboyStudent()
tea=OLdboyTeacher()
obj=Course()
stu.attr=obj
tea.attr=obj
2. 为何要用组合
解决类与类之间代码冗余的问题
4 多态
多态指的是同一种事物的多种形态,
多态性指的是可以在不用考虑对象具体类型前提下而直接使用对象
多态的精髓就是"统一"二字
python崇尚鸭子类型
5 封装
装
封
'''
class Foo:
x=1
def __init__(self,name,age):
self.name=name
self.age=age
def f1(self):
print('run')
# print(Foo.__dict__)
obj=Foo('egon',18)
# print(obj.__dict__)
class A:
def f1(self):
print('A.f1')
super().f2()
class B:
def f2(self):
print('B.f2')
class C(A,B):
def f2(self):
print('C.f2')
obj=C()
print(C.mro())
obj.f1()
'''
A.f1
'''
class People:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
class Teacher(People):
def __init__(self,name,age,sex,level):
# People.__init__(self,name,age,sex)
super().__init__(name,age,sex)
self.level=level
obj=Teacher('egon',18,'male',18)
print(obj.__dict__)