面向对象编程(oop)
类和面向对象(oop)
概述
-
oop思想
任意一个任务,首先想到的是任务的构成和实现过程。 -
类和对象的概念
- 类:抽象名词,代表一个集合,代表一类事物。
- 对象:具象的事物,单个个体。
-
类的内容
- 属性(变量):表明事物特征
- 方法(函数):表明事物功能
-
类的命名
- 大驼峰比较规范。
- 必须用class关键字。
- 由属性和方法组成,其他不许出现。
- 成员属性定义可直接用变量赋值,如果没有值需使用None。
-
访问类和对象的成员
对象成员检查
obj.dict
# 类成员检查
class_name.dict -
实例
定义一个简单的类
class StudentPython():
name = None
age = 18
def Studentplay(self):
print("learning python")David为对象,此时实例化类
David = StudentPython()
print(David.name)
print(David.age)
David.Studentplay()
类和对象的成员分析
-
类和对象都可以储存成员,成员可以归类所有也可以归对象所有。
-
创建对象时,类中的成员不会放入对象中,而是得到一个空对象。
-
通过对象对类中成员重新赋值或者通过对象添加成员时,对应成员会保存在对象中,而不会修改类成员。
-
实例
class Teacher():
name = "aaa"
age = 28
def TeacherSay(self):
self.name = "Mary"
self.age = 20
print("My name is {0}".format(self.name))
print("My age is {0}".format(self.age))t = Teacher()
print(t.name)
print(t.age)
t.TeacherSay()'''
aaa
28
My name is Mary
My age is 20
'''
关于self
-
self在对象的方法中表示当前对象本身,如果通过对象调用方法,那么该对象会自动传入到当前方法的第一个参数中。
-
self并不是关键字,理论上可以用任何一个普通变量名代替。
-
方法中有self形参的称为非绑定类的方法,可以通过对象访问,没有self的称为绑定类方法,只能通过类访问。
-
实例
class Teacher():
name = "aaa"
age = 28
def TeacherSay(self):
self.name = "Mary"
self.age = 20
print("My name is {0}".format(self.name))
print("My age is {0}".format(self.age))
def TeacherSayAgain():
print(class.name)
print(class.age)
print("learning python")t = Teacher()
t.TeacherSay()
# 调用绑定类方法通过类访问
Teacher.TeacherSayAgain()'''
My name is Mary
My age is 20
aaa
28
learning python
'''
面向对象的三大特性
封装,继承,多态
- 封装
-
三个级别:公开(public),受保护(protected),私有(private)。
-
判别对象的位置:对象内部,对象外部,子类中。
-
私有:私有成员是最高级别的封装,只能在当前类或对象中访问,外部不能访问。python的私有不是真私有,是一种为name mangling的改名策略。
class Person():
# name为共有成员
name = "David"
#__age为私有成员
__age = 18 -
受保护:将对象成员进行一定级别的封装,在父类和子类中可以访问,外部不能访问。
-
公开:对对象成员没有任何操作,任何地方都可以访问。
-
- 继承
-
继承就是一个类可以获得另外一个类中的成员属性和方法。
-
被继承的为父类(基类或超类),用于继承的类为子类(派生类)。
-
所有的类都继承自object类,即所有的类都是object类的子类。
-
子类继承父类后并没有将父类成员完全赋值到子类,而是通过引用关系访问调用。
-
子类一旦继承父类,可以使用父类中除私有成员外的所有成员属性和方法,子类还可以定义独有的成员属性和方法。
-
子类中定义的成员如果和父类成员相同,则优先使用子类成员。
-
如果想在子类中扩充父类方法,可以在定义新方法时访问父类成员来进行代码重用,可以
父类名.父类方法也可以super().父类方法的格式调用。
super不是关键字,而是一个类。super的作用是获取MRO(MethodResolutionOrder)列表中的第一个类class Person():
name = "None"
__age = 18
_score = 0
def Study(self):
print("learning python")class Student(Person):
def HaveTest(self):
print("have to take exam")
# 扩充父类函数,方法一二
def Study(self):
Person.Study(self)# 注意这里有self
self.HaveTest()
'''
super().Study()# 注意这里没有self
# super(Student, self).Study()也可以
self.HaveTest()
'''David = Student()
print(David.name)
David.Study()'''
None
learning python
have to take exam
''' -
继承中的查找顺序:子类优先查找自己的变量,没有则查找父类变量;
子类中如果构造函数没有定义,则按照MRO顺序查找调用父类的构造函数,子类有定义则不继续向上查找。
构造函数:每次实例化第一个被自动调用的函数 -
单继承和多继承:单继承每个类只能继承一个类,多继承每个类能继承多个类;单继承逻辑清晰语法简单但功能不能受限,多继承扩展方便但关系混乱且会出现菱形继承(钻石继承)问题。
-
MRO:是在多继承中用于保存继承顺序的一个列表;
MRO计算原则:子类永远在父类前;如果多个父类则根据括号内类的书写顺序存放;如果多个类继承了同一个父类,孙子类中只会选取括号内第一个父类的父类。
-
- 多态
-
多态就是同一个对象在不同情况下有不同状态出现。
-
Mixin设计模式:主要采用多继承方式对类功能进行扩展。首先必须表示某一单一功能,如果有多个功能则写多个Mixin,当子类没有继承某一Mixin类也能照常工作。
class Person():
def init(self, name, age):
self.name = name
self.age = age
def Play(self):
print("have fun")
def Sleep(self):
print("sleeping...")
# 创建一个Mixin
class TeacherMixin():
def Work(self):
print("teaching somebody")class StudentMixin():
def Study(self):
print("learning python")class Student(Person, StudentMixin):
pass
class Teacher(Person):
def init(self):
self.name = "Alex"David = Student("David", 18)
print("my name is {0}, my age is {1}".format(David.name, David.age))
David.Study()
David.Play()
print("*" * 20)
Alex = Teacher()
print("my name is {0}".format(Alex.name))
Alex.Sleep()'''
my name is David, my age is 18
learning python
have fun
********************
my name is Alex
sleeping...
'''
-
类相关函数
- issubclass:检测一个类是否是另一个类的子类。
- isinstance:检测一个对象是否是一个类的实例。
- hasattr:检测一个对象是否有成员xxx。
- dir:获取对象的成员列表
类的成员描述符(属性)
-
类的成员描述符是为了在类中对类的成员属性进行相关操作
-
三种方式:使用类实现描述器;使用属性修饰符;使用property函数
property(fget, fset, fdel, doc)class Person():
'''
property函数实例
定义一个Person类,具有name,age属性,
对于任意输入的name都希望以大写字母保存
'''
def fget(self):
# 返回操作后的属性
return self._name
def fset(self, name):
# 传入需要操作的属性
self._name = name.upper()
def fdel(self):
self._name = "NoName"
name = property(fget, fset, fdel, "None")
age = 18David = Person()
David.name = "David"
print("my name is {0}".format(David.name))
'''
my name is DAVID
'''
类的内置属性
__dict__:以字典的方式显示类成员的组成
__doc__:获取类的文档信息
__name__:获取类的名称,如果在模块中使用则获取模块名称
__bases__:以元组方式显示类的所有父类
类的常用魔术方法
-
魔术方法就是不需要认为调用,在特定的情况下自动触发的方法,统一特征是方法名被前后两个下划线包裹。
__init__:构造函数
__new__:对象实例化方法
__call__:对象当函数时使用
__str__:对象被当作字符串时使用
__repr__:返回字符串
__getattr__:访问一个不存在的属性时触发,此时不会报错
__gt__:进行大于判断的时候触发
__setattr__:对成员属性设置的时候触发__setattr__示例
class A():
def setattr(self, name, value):
print("设置属性{0}为{1}".format(name, value))
'''
这样会导致死循环
self.name = value
'''
# 为了避免这种情况,使用父类魔法函数
super().setattr(name, value)
a = A()
a.age = 18
类和对象的三种方法
-
实例方法:必须要创建实例对象才能调用,第一个参数必须是实例对象,该参数名一般约定为self,如果方法里面有初始化函数也必须对初始化函数进行传参。且只能由实例对象调用
-
类方法:使用装饰器@classmethod,第一个参数必须是当前类对象,该参数名一般约定为cls,可以由实例对象和类对象调用。
-
静态方法:使用装饰器@staticmethod,没有self和cls参数,可以由实例对象和类对象调用。
参考博客Python 实例方法、类方法、静态方法的区别与作用class Person():
def Work(self):
print("have to work")
@classmethod
def Study(cls):
print("have to study")
@staticmethod
def Sleep():
print("sleeping...")
# 实例方法
p = Person()
p.Work()
#Person.Work()会报错
# 类方法
p.Study()
Person.Study()
# 静态方法
p.Sleep()
Person.Sleep()

浙公网安备 33010602011771号