-
对象
对象是指现实中的物体或实体 -
面向对象
把一切堪称对象(实例),让对象和对象之间简历关联关系 -
对象都有什么特征:
属性(名词):姓名,年龄,性别,颜色… … …–>变量
行为(动作):学习,吃饭,睡觉,踢球… … …–>方法 -
什么是类:
用于相同属性和行为的对象分为一组,即为一个类
类是用来描述对象的工具,用类可以创建同类对象 -
Python类名最好使用驼峰命名法:
Mylist MyRange 大驼峰(所有单词首字母大写)
getStudentAge 小驼峰 (第一个首字母小写,其余大写)
说明:因为python内置类为小写,防止命名冲突 -
类的创建语句:
语法:
class 类名(继承列表):
'''类的文档字符串'''
实例方法定义(类内的函数称为方法method)
类变量定义
类方法定义
静态方法定义
- 作用:
创建一个类
用于描述此类对象的行为和属性
类用于创建此类的一个或多个对象(实例) - 类和对象
类 | 对象 实例
class | object instance
- 构造函数
表达式:
类型([创建传参列表])
作用:
创建这个类的实例对象,并返回此实例对象的引用关系
- 实例(对象)说明
实例有自己的作用域和名字空间,可以为该实例添加实例变量(属性)
实例可以调用类方法和实例方法
实例可以访问类变量和实例变量
示例:
class Dog: #Dog是一个变量,绑定一个类
pass
dog = Dog() #dog绑定一个对象
实例方法:
语法:
class 类名(继承列表):
def 实例方法名(self,参数1,参数2,...):
'''实例方法的文档字符串'''
语句块
- 作用:
用于描述一个对象的行为,让此类型的全部对象都拥有相同的行为 - 说明:
实例方法实质是函数,是定义在类内的函数
实例方法至少有一个形参,第一个形参代表调用这个方法的实例,一般命名为’self’ - 实例方法的调用语法:
实例.实例方法名(调用传参)
或
类名.实例方法名(实例,调用传参)
- 属性 attribute(也叫实例变量)
每个实例都可以有自己的变量,此变量称为实例变量(也叫属性) - 属性的使用语法:
实例.属性名 - 赋值规则:
首次为属性赋值则创建此属性
再次为属性赋值必变更属性的绑定关系 - 作用:
用来记录对象自身的数据
实例:
#此实例用来定义一个学生类,并实现添加信息和打印信息的功能
class Student:
def set_info(self,name,age):
'''此方法用来给对象添加姓名和属性'''
self.name = name
self.age = age
def shou_info(self):
print(self.name,'今年',self.age,'岁')
#定义一个Student对象并调用方法
s1 = Student()
s1.set_info('小王',24)
s1.show_info()
- 删除属性
用del语句可以删除一个对象的实例变量
语法:del 对象.实例变量名
示例:
c1 = Cat()
c1.color = '白色' #添加属性
print(c1.color)
del c1.color #删除属性
print(c1.color) #属性错误
- 初始化方法:
作用:对新创建的对象添加实例变量(属性)或相应的资源
语法格式:
class 类名(继承列表):
def __init__(self[,形参列表]):
语句块
说明:
1.初始化方法名必须为__init__不可改变
2.初始化方法会在构造函数创建实例后自动调用,且将实例自身
通过第一个参数self传入__init__方法
3.初始化方法内部如果需要返回则只能返回None
示例:
#此示例示意__init__方法的自动调用及添加实例变量
def Car:
def __init__(self,c,b,m):
print('__init__方法被调用')
self.color = c #颜色
self.brand = b #品牌
self.model = m #型号
a4 = Car('黑色','奥迪','A4')
a4.__init__('黑色','奥迪','A4') #显式调用
#__init__方法具体步骤:
#1.创建一个没有属性的对象
#2.把这个对象传递给__init__方法
#3.引用关系传递给A4
- 析构方法
语法:
class 类名(继承列表):
def __del__(self):
语句块
- 说明:
析构方法在对象销毁时被自动调用 - 作用:清理此对象所占用的资源
示例:
class Car:
def __init__(self,name):
self.name = name
print('汽车',name,'对象已创建')
def __del__(self):
print(self.name,'对象已被销毁')
car1 = Car('奔驰 E6')
#程序结束会自动调用__del__方法
- 注意:python不建议在析构方法内做任何事情,因为对象销毁的时间难以确定
- 预置实例属性
__dict__属性
此属性绑定一个存储此实例自身变量(属性)的字典
示例:
class Dog:
pass
dog1 = Dog()
print(dog1.__dict__) #{}
dog1.color = '白色'
print(dog1.__dict__) #{'color':'白色'}
#键值对赋值
dog1.__dict__['age'] = 3
__class__属性
此属性用来绑定创建此实例的类
作用:
可以借助此属性来访问创建此实例的类
dog2 = dog1.__class__() #等同于dog2 = Dog()
- 用于类的函数:
isinstance(obj,class_or_tuple)
#返回这个对象obj是否某个类class或某些类的实例,如果时则返回
#True,否则返回False
#实例:
animal = Dog()
isinstance(animal,(Cat,int)) #返回False
isinstance(aninal,(Dog,int)) #返回True
Type(obj) #返回对象的类型
- 类变量(class variable)
类变量是类的属性,此属性属于类 - 作用:
用来记录类相关的数据 - 说明:
类变量可以通过类直接访问(所有的对象所共有)
类变量可以通过类的实例直接访问
类变量可以通过此类实例的__class__属性间接访问
示例:
#此示例示意类变量的定义和使用
class Human:
count = 0
print('Human的类变量count=',Human.count) #0
Human.count = 100
print(Human.count) #100
#以下示意类变量与示例变量的区别及示例间接访问类变量
h1 = Human()
h1.count = 200
print(h1.count) #200
print(Human.count) #100
h1.__class__.count +=200
print(h1.count) #200
print(Human.count) #300
- 类变量的应用案例:
#用类变量记录对象的个数
class Car:
count = 0 #创建类变量,用来记录汽车对象总数
def __init__(self,info):
print(info,'被创建')
self.data = info
self.__class__.count+=1 #让汽车的总数加1
def __del__(self):
print(self.data,'被销毁')
#当车被销毁时总数自动减1
self.__class__.count -= 1
print('当前汽车总数是:',Car.count)
b1 = Car('BYD 京A.88888')
print('当前汽车总数是:',Car.count)
b2 = Car('TESLA 京B.88888')
print('当前汽车总数是:',Car.count)
del b1
print('当前汽车总数是:',Car.count)
-
类的文档字符串
类内第一个没有赋值给任何变量的字符串是类的文档字符串 -
说明:
类的文档字符串用类的__doc__属性可以访问
类的文档字符串可以用help()函数访问 -
类的__slots__列表
作用:限定一个类的实例只能有固定的属性(实例变量)
通常为当错写属性名时不添加属性而是发出报告 -
说明:
含有__slots__列表的类创建的实例对象没有__dict__属性,
即此实例不用字典来保存对象的属性(实例变量)(因为字典为可变的而__slots__限制了不可变)
示例:
#此示例示意类的变量__slots__列表的作用
class Student:
__slots__ = ['name','score'] #限制类只拥有这两个属性
def __init__(self,name,score):
self.name = name
self.score = score
s1 = Student('小李',68)
print(s1.score)
s1.scrce = 100 #此处错写了属性名,若无__slots__列表将不会报错
print(s1.score)
print(s1.__dict__)#发生AttributeError,此对象没有__dict__属性
- 类方法@classmethod
类方法是描述类的行为的方法,类方法属于类 - 说明:
类方法需要用@classmethod装饰器定义
类方法至少有一个形参,第一个形参用于绑定类,约定写为’cls’
类和该类的实例都可以调用类方法
类方法不能访问此类创建的实例的属性(只能访问类变量)
示例:
#此示例示意类方法的使用
class Car:
count = 0 #类变量
@classmethod
def getTotalCount(cls): #传参业内规定写cls
'''此方法为类方法,得到类变量'''
return cls.count
@classmethod
def updateCount(cls,number):
'''此方法为类方法,更新类变量'''
cls.count+=number
print(Car.getTotalCount()) #用类来调用类方法
#Car.count +=1 #面向对象思想不提倡直接操作属性
Car.updateCount(1)
print(Car.getTotalCount()) #1
c1 = Car() #创建一个对象
c1.updateCount(100) #Car类的示例也可以调用类方法 实际上
#相当于把c1.__class__传入cls参数
print(c1.getTotalCount()) #101
c2 = Car()
c2.count = 200 #实例属性
print(c2.getTotalCount()) #200,类方法不能访问实例的属性
- 总结:
以上分别介绍了类变量、类方法
实例变量、实例方法
此外还有不属于类和实例的静态方法 - 静态方法@staticmethod
静态方法不属于类,也不属于类的实例,它相当于定义在类内的普通函数,只是它的作用域属于类
示例:
#此示例示意静态方法的创建和使用
class A:
@staticmethod
def myadd(a,b):
'''此方法为静态方法
此方法的形参不需要传入类和实例'''
return a+b
print('1+2 = ',A.myadd(1,2)) #类调用
a = A() #对象调用
print('100+200 = ',a.myadd(100,200))
- 继承inheritance 和 派生derived
(1)继承是指从已有的类中衍生出新类,新类具有原类的行为,并能扩展新的行为
(2)派生就是从一个已有类中衍生(创建)新类,在新类上可以添加新的属性和行为 - 继承和派生的目的:
继承是延续旧类的功能
派生是为了在旧类的基础上添加新的功能 - 作用:
(1)用继承派生机制,可以将一些共有功能加在基类中,实现代码的共享
(2)在不改变基类的基础上改变原有功能 - 继承/派生的名词
基类(base class),超类(super),父类(father class)
派生类(derived class)/子类(child class) - 单继承
语法:
class 类名(基类名):
语句块
说明:单继承是指派生类由一个基类衍生出来的类
示例:
#此示例用来示意继承和派生
class Human:
'''此类用来描述人类的共性行为'''
def say(self,word):
print('say',word)
def walk(self,distance):
print('走了',distance,'公里')
class Student(Human):
'''学生类单继承Human类并派生新的方法'''
def study(self,subject):
print('正在学习',subject)
s1 = Student()
s1.say('今天天气真好')
s1.walk(5)
s1.study('Python')
- 继承说明:
任何类都直接或间接的继承自object类
object类是一切类的超类(组类,亚当夏娃级的类)
例如:class Human(): #也可写成class Human(object): - 类的__base__属性:
__base__属性用来记录此类的基类
示例:
class Human:
pass
class Student(Human):
pass
class Teacher(Student):
pass
t1 = Teacher()
t1.__base__ #Student
t1.__base__.__base__ #Human
Human.__base__ #object
object.__base__ #None
#示意bool的基类
True.__base__ #bool
True.__base__.__base__ #int
int.__base__ #object
- 覆盖 override
覆盖是指在有继承关系的类中,子类中实现了与基类同名的方法,在子类实例调用该方法时,实例调用的是子类中的覆盖版本的方法,这种现象叫做覆盖
示例:
class A:
def work(self):
print('A.work()被调用')
class B(A):
def work(self):
print('B.work被调用') #覆盖父类方法
b = B()
b.work()
b.__class__.__base__.work(b) #虽然覆盖子类也能调用父类的方法
- 子类对象显式调用基类方法的方式:
基类名.方法名(实例,实际调用传参) - super函数
super(type,obj)返回绑定超类的实例
super() 返回绑定超类的实例,等同于:(必须在子类方法内调用)
super(__class__,实例方法的第一个参数)
示例:
class A:
def work(self):
print('A.work被调用')
class B(A):
def work(self):
print('B.work被调用')
def super_work(self):
#super(B,self).work() #A.work()
#super(__class__,self).work() #A.work()
super().work() #A.work()必须在方法内调用
b = B()
b.super_work() #A.work()
- 显式调用基类的初始化方法:
当子类中实现了__init__方法时,基类的__init__方法并不会被自动调用,此时需要使用super显式调用
示例:
class Human:
def __init__(self,n,a):
self.name = n
self.age = a
def info():
print('姓名:',self.name)
print('年龄:',self.age)
class Student(Human):
def __init__(self,n,a,s):
super().__init__(n,a)#使用super显式调用基类初始化方法
self.score = s
def info(self):
super().info()
print('成绩:',self.score)
s1 = Student('小王',23,100)
s1.info()
- 用于类的函数:
isinstance(obj,cls)
判断对象obj是否是cls的对象,若cls是obj的类或父类则返回True
否则返回False
issubclass(cls,class_or_tuple)
判断一个类cls是否继承自class_or_tuple,返回True或False
查看python内建类继承关系的方法:
help(__builtins__ )
示例:
class A:
pass
class B(A):
pass
class C(B):
pass
issubclass(C,(A,B)) #True
issubclass(C,object) #Ture
- 封装 enclosure
封装是指隐藏类的实现细节,让使用者不用关心这些细节
封装的目的是让使用者尽可能少的使用实例变量进行操作 - 私有属性:
python类中,以双下划线’__'开头,不以双下划线结尾的标识符为私有成员,在类的外部无法直接访问
示例:
class A:
def __init__(self):
self.__p1 = 100 #__p1为私有属性,在外部不可访问
def test(self):
print(__p1)
self.__m1() #A类的方法可以调用A类的私有方法
def __m1(self): #__m1为私有方法
print('m1方法被调用')
a = A()
print(a.__p1) #在类外看不到__p1属性,访问失败!
a.test() #使用方法访问私有属性
a.__m1() #调用失败,外部无法调用私有方法,且只有
#A类才能调用
- 多态 polymorphic
字面意思:“多种状态”
多态是指在继承/派生关系的类中调用基类对象的方法。实际上,能调用子类覆盖版本方法的现象叫多态 - 说明:
多态调用的方法与对象无关,不与类型相关
python的全部对象都只有‘运行时状态(动态)’,没有‘C++/Java’里的’编译时状态(静态)’
示例:
class Shape:
def draw(self):
print('Shape.draw被调用')
class Point(Shape):
def draw(self):
print('正在画一个点')
class Circle(Point):
def draw(self):
print('正在画一个圆')
def my_draw(s): #不是C++/java必须要先指定s的类型
s.draw() #此处显示多态中的动态
s1 = Point()
s2 = Circle()
my_draw(s1)
my_draw(s2)
- 面向对象的编程语言的特征
继承
封装
多态
如:C++/ Java/ Python/ Swift/ C# - 多继承 multiple inheritance
多继承是指一个子类继承自两个或两个以上的基类
语法:
class 类名(基类名1,基类名2,........):
语句块
- 说明:
(1)一个子类同时继承自多个父类,父类中的方法可以同时被继承下来
(2)如果两个父类中由同名的方法,而在子类中又没有覆盖此方法时,调用结果难以确定 - 多继承的缺陷:
标识符(名字空间冲突的问题)
要谨慎使用多继承
示例:
class Car:
def run(self,speed):
print('汽车正在以',speed,’的速度行驶')
def test(self): #演示名字冲突
print('Car.test被调用’)
class Plane:
def fly(self,height):
print('飞机正在海拔',height,'的高度飞行')
def test(self):
print('Plane.test被调用')
class CarPlane(Car,Plane): #飞车继承飞机和汽车类
pass
cp = CarPlane()
cp.fly(10000) #调用成功
cp.run(100) #调用成功
cp.test() #CarPlane中没有覆盖,父类名称冲突
#会调用继承列表(Car,Plane)中的第一个,这里是Car
#之后会类似广度优先的遍历(C3算法)-->python3
- 继承的MRO(Method Resolution Order)问题
类内的__mro__属性用来记录继承方法的查找顺序
示例:
#此示例用来演示类的__mro__属性
class A:
def m(self):
print('A.m')
class B(A):
def m(self):
print('B.m')
super().m() #调用C.m不是A,因为继承调用是按mro顺序
class C(A):
def m(self):
print('C.m')
class D(B,C):
def m(self):
print('D.m')
super().m() #调用B.m
d = D()
print(D.__mro__) #D,B,C,A,object
总结:单继承中super一定调用继承列表内的父类
而多继承中的super不一定是父类,按照mro的广度优先列表\
练习:
#自定义Mylist类继承自list类并添加insert_head功能
class Mylist(list):
def insert_head(self,value):
self.insert(0,value) #可以直接使用父类的方法
L = Mylist(range(1,5)) #直接使用父类的初始化方法
print(L)
L.insert_head(0)
print(L)
L.append(5)
print(L)
- 函数重写 override
重写是在自定义的类中添加相应的方法,让自定义的类生成的对象(实例)像内建对象一样进行内建的函数操作 - 对象转字符串函数重写:
repr(obj) 返回一个能代表此对象的表达式字符串,通常:
eval(repr(obj)) == obj
str(obj) 通过给定的对象返回一个字符串(这个字符串通常是
给人看的,没有字符两边的引号)
例如:
s = 'I am a Human'
s1 = repr(s) #eval(s1)返回s,能完全代表s的字面值
s2 = str(s)
print(s1) #'I am a Human' 是表达式
print(s2) #I am a Human
示例:
class MyNumber:
def __len__(self):
return 100
n1 = MyNumber()
x = len(n1) #重写了__len__方法才能这样调用
print('x = ',x)
- repr和str的重写:
repr()函数的重写方法:
def __repr__(self):
return 能够表达self内容的字符串
str()函数的重写方法:
def __str__(self):
return 人能看懂的字符串
说明:
(1)str(obj)函数优先调用obj.__str__()方法返回字符串
(2)如果obj没有__str__()方法,则调用obj.__repr__()方法返回
的字符串
(3)如果obj没有__repr__()方法,则调用object类的__repr__()实
例方法显示<xxxx>格式的字符串
(4)__str__ 在用户调用print打印对象时,该方法会自动执行。
(5)__repr__ 在机器(在python命令行中实例化对象后,再只写个对象名
回车)使用时自动执行。
注意:在没有写__str__方法的时候,且写了repr方法时。__str__=
__repr__
示例:
#此示例演示重写__repr__与__str__方法
class Student:
def __init__(self,name):
self.__name = name
def __str__(self):
return str(self.__name)
def __repr__(self):
return repr(self.__name)
s1 = Student('小王')
print(s1) #小王,优先调用__str__,
#若没有__str__而有__repr__则是'小王'
- 其余函数的重写只需在类内加前后双下划线即可
如内建函数的重写:
__abs__ __int__
__complex__ __float__
__reversed__ __bool__
__round__ __len__
- 布尔测试函数的重写
格式:
def __bool__(self):
...
作用:
用于bool(obj)函数取值
用于if语句真值表达式中(若有__bool__方法,if obj会自动调用
并判断,否则__len__判断之后无条件为真)
用于while语句真值表达式中
说明:
1.优先调用__bool__()方法取值
2.如果不存在__bool__()方法,则调用__len__()方法去之后判断
是否为0值,不为0返回True,否则返回False
3.如果再没有__len__()方法,则直接返回True
示例:
#此示例示意bool函数的重写与len函数重写的关系
class Mylist:
def __init__(self,iterator = []):
self.data = [x for x in iterator]
#def __bool__(self):
# return bool(self.data)
#def __len__(self): #当没有bool重写时使用len重写
#的结果判断
# return len(self.data) #若同时没有len重写,则无条件
#返回True
l = Mylist([])
if l:
print('Ture')
else:
print('False')
- 迭代器(高级)
什么是迭代器:可以通过next(it)函数取值的对象
迭代器协议:
迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据时触发一个StopIterator来终止迭代的约定
实现方法:
类内需要有__next__(self)方法来实现迭代器协议
语法形式:
class MyIterator:
def __next__(self):
迭代器协议的实现
return 数据
- 什么是可迭代对象:
是指能用iter(obj)函数返回迭代器的对象(实例)
可迭代对象内部一定要定义__iter__(self)方法来返回迭代器 - 什么是迭代器:
类用用于__next__方法的叫做迭代器
__next__方法必须符合迭代器协议 - 可迭代对象的语法形式:
class MyIterable:
def __iter__(self):
语句块
return 迭代器 #必须返回迭代器
练习:
class Fibonacci:
def __init__(self,n):
'''此方法用于初始化Fib数列'''
self.__count = n
if n==1:
self.__it = [1]
elif n==2:
self.__it = [1,1]
elif n>2:
tmp = 2
self.__it = [1,1]
while tmp<=n:
self.__it.append(self.__it[tmp-1]+self.__it[tmp-2])
tmp+=1
def __iter__(self):
'''将Fib作为可迭代对象,必须返回迭代器'''
return MyIterator(self.__it) #此处也可以使用内建的迭代器
#如return iter(self.__it)
def __repr__(self):
'''向Fib数列提供打印功能'''
return '%r' % self.__it
class MyIterator:
'''自建迭代器(拥有__next__方法且方法返回值才算迭代器)'''
def __init__(self,iterable):
self.__cur = 0
self.__it = iterable
def __next__(self):
'''迭代器协议'''
if self.__cur >=len(self.__it):
raise StopIteration
self.__r = self.__it[self.__cur]
self.__cur+=1
return self.__r
def __str__(self):
'''向迭代器提供打印功能'''
return str(self.__r)
for x in Fibonacci(10):
print(x)
L = [x for x in Fibonacci(30)]
print(L)
print(sum(Fibonacci(25)))