对象是指现实中的物体或实体
面向对象:把一切看成对象(实例),让对象和对象之间建立关联关系
对象的特征:对象有很多的属性(名词: 姓名,性别,年龄);
对象有很多行为(动词: 学习,吃饭,睡觉,看书)
类是拥有相同属性和行为的对象分为一组,即为一个类,类是用来描述对象的工具,用类可以创建同类对象。
车(类)-----------> BYD E6(京A.88888) 实例
车(类)-----------> BMW X5(京A.00000) 实例
狗(类)----------->小京巴(户籍号:000001)
----------->导盲犬(户籍号:000002)
int(类)----------->100(对象/实例)
----------->200(对象/实例)
类的创建语句:
语法:class 类名(继承列表):
‘’‘类的文档字符串’’’
实例方法定义(类内的函数称为方法method)
类变量定义
类方法定义
静态方法定义
作用:创建一个类
用于描述词类对象的行为和属性
类用于创建此类的一个或多个对象(实例)
示例:
# 此示例示意类的定义
class Dog: # 定义一个类,类名为Dog
pass
dog1 = Dog() # 构造函数,创建Dog类的对象
print(id(dog1)) # 4378526216
dog2 = Dog() # 创建Dog类的另一个对象
print(id(dog2)) # 4382983672
# 类似于如下语法:
int1 = int()
int2 = int()
类 对象 实例
class | object | instance
表达式:
类名([创建传参列表])
作用:创建这个类的实例对象,并返回此实例对象的引用关系
实例(对象)说明:实例有自己的作用域和名字空间,可以为该实例添加实例变量(属性);实例可以调用类方法和实例方法;实例可以访问类变量和实例变量
示例:
class Dog:
pass
dog1 = Dog()
实例方法:
语法:
class 类名(继承列表):
def 实例方法名(self, 参数1, 参数2, …):
‘’‘实例方法的文档字符串’’’
语句块
作用:用于描述一个对象的行为,让此类型的全部对象都拥有相同的行为
说明:实例方法实质是函数,是定义在类内的函数;
实例方法至少有一个形参,第一个形参代表调用这个方法的实例, 一般命名为’self’
实例方法的调用语法:
实例.实例方法名(调用参数)
或
类名.实例方法名(实例,调用传参)
示例:
# 此实例示意如何用实例方法(method)来描述Dog类的行为
class Dog:
def eat(self, food):
'''此方法用来描述小狗吃东西的行为'''
print("小狗正在吃:", food)
def sleep(self, hour):
print("小狗睡了", hour, "小时")
# 创建一个Dog类的实例:
dog1 = Dog()
dog1.eat("狗粮") # 小狗正在吃: 狗粮
dog1.sleep(10) # 小狗睡了 10 小时
# dog1.play("球") # 对象不能调用类内不存在的方法
# 创建另一个Dog对象
dog2 = Dog()
dog2.eat("骨头")
dog2.sleep(2)
# 可以用下面的方法调用方法
Dog.eat(dog2, '苹果')
属性也叫实例变量,每个实例都可以有自己的变量,此变量称为实例变量(也叫属性)
属性的使用语法:实例.属性名
赋值规则:首次为属性赋值则创建此属性;再次为属性赋值则改变属性的绑定关系
作用:用来记录对象自身的数据
实例:
# 此示例示意为对象添加属性
class Dog:
pass
# 创建第一个对象
dog1 = Dog()
dog1.kinds = '京巴' # 添加属性kinds
dog1.color = '白色' # 添加属性color
dog1.color = '黄色'
print(dog1.color, '的', dog1.kinds) # 访问属性
dog2 = Dog()
dog2.kinds = '牧羊犬'
dog2.color = '灰色'
实例方法和实例变量(属性)结合在一起使用:
示例:
class Dog:
def eat(self, food):
print(self.color, '的', self.kinds, '正在吃', food)
# 创建第一个对象
dog1 = Dog()
dog1.kinds = '京巴' # 添加属性kinds
dog1.color = '白色' # 添加属性color
dog1.color = '黄色'
#print(dog1.color, '的', dog1.kinds) # 访问属性
dog1.eat('骨头')
dog2 = Dog()
dog2.kinds = '牧羊犬'
dog2.color = '灰色'
dog2.eat('包子')
class Student:
def set_info(self, name, age=0):
'''此方法用来给学生对象添加姓名和年龄属性'''
self.name = name
self.age = age
return self.name, self.age
def show_info(self):
'''此处显示学生的信息'''
print(self.name, '今年', self.age, '岁')
s1 = Student()
s1.set_info('xiaomaomao', 1)
s2 = Student()
s2.set_info('xiaoxiaomao', 1)
s1.show_info()
s2.show_info()
用del语句可以删除一个对象的实例变量
语法:del 对象.实例变量名
示例:
class Cat:
pass
cat1 = Cat() # 创建对象
c1.color = '白色' # 添加属性
print(c1.color)
del c1.color # 删除属性
print(c1.color) # 属性错误
作用:对新创建的对象添加实例变量(属性)或相应的资源
语法格式:class 类名(继承列表):
def init(self [, 形参列表])
语句块
说明:(1) 初始化方法名必须__init__不可改变;
(2) 初始化方法会在构造函数创建实例后自动调用,且实例自身通过第一个参数self传入__init__方法;
(3) 构造函数的实参将通过__init__方法的形参列表传入__init__方法中;
(4) 初始化方法内部如果需要返回则只能返回None
示例:
# 此示例示意__init__方法的自动调用及添加示例变量
class Car:
def __init__(self, c, b, m):
self.color = c # 颜色
self.band = b # 品牌
self.model = m # 型号
def run(self, speed):
print(self.color, '的', self.band, self.model,
'正在以', speed, '公里/小时的速度行驶')
def set_color(self, clr):
'''此方法用来修改车的颜色信息'''
self.color = clr
a4 = Car('红色', '奥迪', 'A4')
a4.run(179) # # 红色 的 奥迪 A4 正在以 179 公里/小时的速度行驶
#a4.color = '黑色'
a4.set_color('黑色')
a4.run(300) # 黑色 的 奥迪 A4 正在以 300 公里/小时的速度行驶
t1 = Car('蓝色', 'TESLA', 'Modle S')
t1.run(299) # 蓝色 的 TESLA Modle S 正在以 299 公里/小时的速度行驶
# a4.__init__('白色', 'Tesla', 'Model S') # 显式调用__init__
语法:
class 类名(继承列表):
del(self):
语句块
说明:析构方法在对象销毁时被自动调用
作用:清理此对象所占用的资源
示例:
# 此示例示意__del__方法的用法
class Car:
def __init__(self, name):
self.name = name
print("汽车", name, "对象已经创建")
def __del__(self):
print(self.name, "对象已经销毁")
c1 = Car("BYD") # 汽车 BYD 对象已经创建
c1 = Car("BMW")
python不建议在析构方法内做任何事情,因为对象销毁的时间难以确定。
__dict__属性:此属性绑定一个存储此实例自身变量的字典
示例:
class Dog:
pass
dog1 = Dog() # 创建一个Dog类型的实例
print(dog1.__dict__) # {}
dog1.kinds = '京巴'
print(dog1.__dict__) # {'kinds': '京巴'}
dog1.color = '白色'
print(dog1.__dict__) # {'kinds': '京巴', 'color': '白色'}
print(dog1.color) # 白色
__class__属性: 此属性用来绑定创建此实例的类
作用:可以借助此属性来访问创建此实例的类
示例:
class Dog:
pass
dog1 = Dog()
print(dog1.__class__) #
dog2 = Dog()
dog3 = dog1.__class__() # 等同于dog1 = Dog(),创建dog1的同类对象
下面示例示意如何用面向对象的方式创建对象,并建立对象与对象之间的逻辑关系
# 此示例示意如何用面向对象的方式创建对象,并建立对象与对象之间的逻辑关系
class Human:
'''人类,用于描述人的行为'''
def __init__(self, n, a):
self.name = n # 姓名
self.age = a # 年龄
self.money = 0 # 钱数为0
def teach(self, other, skill):
print(self.name, "教", other.name, "学", skill)
def works(self, money):
self.money = self.money + money
print(self.name, "工作赚了", self.money, "元钱")
def borrow(self, other, money):
if other.money > money:
print(other.name, "借给", self.name, money, "元钱")
self.money = self.money + money
other.money = other.money - money
else:
print(other.name, "不借给", self.name, "钱")
def show_info(self):
print(self.age, "岁的", self.name, "存有", self.money, "元钱")
# 以下为类的使用
xiaomaomao = Human('xiaomaomao', 1)
xiaoxiaomao = Human('xiaoxiaomao', 1)
xiaoxiaomao.teach(xiaomaomao, 'Python') # xiaoxiaomao 教 xiaomaomao 学 Python
xiaomaomao.teach(xiaoxiaomao, 'Java') # xiaomaomao 教 xiaoxiaomao 学 Java
xiaoxiaomao.works(1000) # xiaoxiaomao 工作赚了 1000 元钱
xiaomaomao.borrow(xiaoxiaomao, 200) # xiaoxiaomao 借给 xiaomaomao 200 元钱
xiaoxiaomao.show_info() # 1 岁的 xiaoxiaomao 存有 800 元钱
isinstance(obj, class_or_tuple) # 返回这个对象obj是否某个类class或某些类的实例,如果是则返回True,如果否则返回False
type(obj) # 返回对象的类型
class Dog:
pass
class Cat:
pass
animal = Dog()
isinstance(animal, Dog)
isinstance(animal, Cat)
isinstance(animal, (Cat, int, list)) # False
isinstance(animal, (Cat, int, Dog)) # True
type(animal) # , 等同于animal.__class__
类变量是类的属性,此属性属于类
作用:用来记录类的相关数据
说明:类变量可以通过类直接访问;类变量可以通过类的实例直接访问;类变量可以通过此类的实例的__class__属性间接访问
示例:
# 此示例示意类变量的定义和使用
class Human:
count = 0 # 创建一个类变量
# 通过类直接访问
print("Human的类变量count=", Human.count) # Human的类变量count= 0
Human.count = 100
print(Human.count) # 100
# 通过类的实例直接访问类变量
human1 = Human()
print(human1.count) # 100
# 通过类示例.__class__访问类变量
human2 = Human()
human2.count = 200
print(human2.count) # 200
print(human2.__class__.count) # 100
类变量的应用案例:用类变量来记录对象的个数
class Car:
count = 0 # 创建类变量,用来记录汽车对象的总数
def __init__(self, info):
print(info, "被创建")
self.data = info # 记录传入数据
self.__class__.count = self.__class__.count + 1 # 让车的总数加1
def __del__(self):
print(self.data, "被销毁")
self.__class__.count = self.__class__.count - 1 # 当车被销毁时自动减1
print(Car.count) # 0
b1 = Car("BYD")
print(Car.count) # 1
b2 = Car("BMW")
print(Car.count) # 2
b3 = Car("Audi")
print(Car.count) # 3
类内第一个没有赋值给任何变量的字符串是类的文档字符串
说明:类的文档字符串用类的__doc__属性可以访问;类的文档字符串可以用help()函数查看
示例:
'''
模块的标题
此模块示意类的文档字符串
'''
class Car:
'''
此类用来描述车的对象的行为
这是Car类的文档字符串
'''
def run(self, speed):
'''
车的run方法
'''
pass
作用:限定一个类的实例只能有固定的属性(实例变量),通常为防止错写属性名而发生运行时错误
示例:
# 此示例示意类变量__slots__列表的作用
class Student:
__slots__ = ['name', 'score']
def __init__(self, name, score):
self.name = name
self.score = score
s1 = Student('xiaomaomao', 100)
print(s1.score) # 100
s1.socre = 90 # 不加slots时写错了属性名,但在运行时不会报错;添加了slots列表后运行会报错
print(s1.score) # 100
说明:含有__slots__列表的类创建的实例对象没有__dict__属性,即此实例不用字典保存对象的属性(实例变量)
类方法是描述类的行为的方法,类方法属于类
说明:(1)类方法需要用@classmethod装饰器定义;(2)类方法至少有一个形参,第一个形参用于绑定类,约定写为’cls’; (3)类和该类的实例都可以调用类方法;(4)类方法不能访问此类创建的实例的属性(只能访问类变量)
示例:
# 此示例示意类方法的定义和用法
class Car:
count = 0 # 类变量
@classmethod
def getTotalCount(cls):
'''此方法为类方法,第一个参数为cls,代表调用此类方法'''
return cls.count
@classmethod
def updateCount(cls, number):
cls.count = cls.count + 1
print(Car.getTotalCount()) # 用类来调用类方法 0
#Car.count = Car.count + 1 # 不提倡直接直接操作类变量
Car.updateCount(1) # 使用类方法操作类变量
print(Car.getTotalCount()) # 1
c1 = Car() # 创建一个对象
c1.updateCount(100) # Car类的实例也可以调用类方法
print(c1.getTotalCount()) # 101
# 此示例示意类方法的定义和用法
class Car:
count = 0 # 类变量
@classmethod
def getInfo(cls):
return cls.count
c1 = Car() # 创建一个对象
c1.count = 100
print(c1.getInfo()) # 0 拿到的是类里面的变量
问题:(1)类方法属于类
(2) 实例方法属于该类的实例
(3) 类内能不能有函数,这个函数不属于类,也不属于实例。这样的方法是静态方法。
静态方法不属于类,也不属于类的实例,它相当于定义在类内的普通函数,只是它的作用域属于类
示例:
# 此示例示意静态方法的创建和使用
class A:
@staticmethod
def myadd(x, y):
'''
此方法为静态方法
此方法的形参不需要传入类或实例
'''
return x + y
print('1+2=', A.myadd(1, 2))
a = A()
print('100+200=', a.myadd(100, 200))
继承:继承是指从已有的类中派生出新类,新类具有原类的行为,并能扩展新的行为。
派生:派生是从一个已有类中衍生(创建)新类, 在新类上可以添加新的属性和行为
继承和派生的目的:继承是延续旧类的功能;派生是为了在旧类的基础上添加新的功能
作用:
(1)用继承派生机制,可以将一些共有功能加在基类中,实现代码的共享
(2) 在不改变基类的基础上改变原有功能
继承/派生的名词:
基类(base class),超类(super class),父类(father class),派生类(derived class),子类(child class)
语法:
class 类名(基类名):
语句块
说明:单继承是指派生类由一个基类衍生出来的类
示例:
class Human:
'''此类用来描述人类的共性行为'''
def say(self, that):
print("say: ", that)
def walk(self, distance):
print("walk: ", distance, "kms")
class Student(Human):
def study(self, subject):
print("studying: ", subject)
class Teacher(Student):
def teach(self, subject):
print("teaching: ", subject)
h1 = Human()
h1.say("todday is very cold")
h1.walk(5)
s1 = Student()
s1.say("todday is very cold")
t1 = Teacher()
t1.say("tommorrow is Saturday")
t1.walk(6)
t1.teach("object oriented")
t1.study("piano")
继承说明:任何类都直接或间接继承自object类,object类是一切类的超类(祖类)
类的__base__属性:__base__属性用来记录此类的基类
覆盖:覆盖是指在有继承关系中的类中,子类中实现了与基类同名的方法,在子类实例调用该方法时,实例调用的是子类中的覆盖版本的方法,这种现象叫做覆盖。
示例:
# 此示例示意覆盖的用法
class A:
def work(self):
print("A.work()被调用")
class B(A):
'''B继承自A类'''
def work(self):
print("B.work()被调用")
a = A()
a.work() # A.work()被调用
b = B()
b.work() # B.work()被调用
b.__class__.__base__.work(b) # A.work()被调用
子类对象显式调用基类方法的方式:
基类名.方法名(实例, 实例调用传参)
super函数:
super(type, obj)返回绑定超类的实例
super()返回绑定超类的实例,等同于super(class, 实例方法的第一个参数)(必须在方法内调用)
示例:
# 此示例示意super函数来调用父类的覆盖版本方法
class A:
def work(self):
print("A.work()被调用")
class B(A):
'''B继承自A类'''
def work(self):
print("B.work()被调用")
def super_work(self):
# 在方法内调用父类的方法
# self.work() # B.work()
# super(B, self).work() # A.work()
super().work() # A.work()
b = B()
b.__class__.__base__.work(b) # 调用父类的work方法 A.work()被调用
super(B, b).work() # 调用超类的方法 A.work()被调用
b.super_work() # A.work()被调用
显示调用基类的初始化方法:
当子类中实现了__init__方法时,基类的__init__方法并不会被自动调用,此时需要显式调用。
示例:
# 此示例示意子类对象用super方法显示调用基类的__init__方法
class Human:
def __init__(self, n, a):
'''此方法为人的对象添加姓名和年龄属性'''
self.name = n
self.age = a
def infos(self):
print("name: ", self.name)
print("age: ", self.age)
class Student(Human):
def __init__(self, n, a, s=0):
super().__init__(n, a)
self.score = s
def infos(self):
super().infos()
print("score: ", self.score)
s1 = Student("xiaoxiaomao", 1, 100)
s1.infos()
issubclass(cls, class_or_tuple): 判断一个类是否继承自其它的类,如果此类cls是class或tuple中的一个派生子类则返回True,否则返回False
示例:
class A:
pass
class B(A):
pass
class C(B):
pass
issubclass(C, (A, B)) # True
issubclass(C, (int, str)) # False
issubclass(C, A) # True
查看python内建类的继承关系的方法:
help(builtins)
封装是指隐藏类的实现细节,让使用者不用关心这些细节,封装的目的是让使用者尽可能少的使用实例变量(属性)进行操作。
私有属性:python类中,以双下划线‘__’开头,不以双下划线结尾的标识符为私有成员,在类的外部无法直接访问。
# 此类示意使用私有属性和私有方法
class A:
def __init__(self):
self.__p1 = 100 # __p1为私有属性,在类的外部不可以访问
def test(self):
print(self.__p1) # 可以访问,A类的方法可以调用A类的私有方法
def __m1(self):
'''私有方法,只有在类的内部方法才能调用此方法'''
print("我是A类的__m1方法")
a = A() # 创建对象
#print(a.__p1) # 在类外看不到__p1属性,访问失败
a.test() # 100
a.__m1() # 出错,无法调用私有方法
字面意思:“多种状态”
多态是指在继承/派生关系的类中,调用基类对象的方法,实现能调用子类的覆盖版本方法的现象叫多态
说明:多态调用的方法与对象相关,不与类型相关;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):
s.draw() # 调用那个类具体要看传进来的参数是哪个类中的
s1 = Circle()
s2 = Point()
my_draw(s1) # 调用Circle里的draw
my_draw(s2) # 调用Point里的draw
多继承是指一个子类继承自两个或两个以上的基类
语法:
class 类名(基类名1, 基类名2, …):
语句块
说明:(1) 一个子类同时继承自多个父类,父类中的方法可以同时被继承下来;
(2) 如果两个父类中有同名的方法,而在子类中又没有覆盖此方法时,调用结果难以确定
示例:
# 此示例示意多继承语句和使用
class Car:
def run(self, speed):
print("以", speed, "公里/小时的速度行驶")
class Plane:
def fly(self, height):
print("飞机以海拔", height, "的高度飞行")
class PlaneCar(Car, Plane):
'''
PlaneCar同时继承自汽车类和飞机类
'''
p1 = PlaneCar()
p1.fly(10000)
p1.run(300)
多继承的问题(缺陷)
标识符(名字空间冲突的问题),要谨慎使用多继承
示例:
# 此示例示意多继承可能出现的问题
# 小猫猫写了一个类A
class A:
def m(self):
print("A.m()被调用")
# 小小猫写了一个类B
class B:
def m(self):
print("B.m()被调用")
# 诗诗用小猫猫和小小猫写的类
class AB(A, B):
pass
ab = AB()
ab.m() # A.m()被调用,但是B.m()中也有m方法,在实际复杂的问题中很难控制哪一个被调用
类内的__mro__属性用来记录继承方法的查找顺序
示例:
# 此示例示意在多继承中的方法查找顺序问题
class A:
def m(self):
print("A.m")
class B:
def m(self):
print("B.m")
class C(A):
def m(self):
print("C.m")
super().m() # super()是按照MRO顺序来打印的,而不是按照父类的继承来调用的
class D(B, C):
def m(self):
print("D.m")
super().m()
d = D()
print(D.__mro__) # (, , , , )
d.m() # 调用方法的顺序D,B,C,A
重写是指在自定义的类内添加相应的方法,让自定义的类生成的对象(实例)像内建对象一样进行内建的函数操作
repr(obj)返回一个能代表此对象的表达式字符串,通常eval(repr(obj)) == obj
def repr(self):
return 能够表达self内容的字符串
str(obj)通过给定的对象返回一个字符串(这个字符串通常是给人看的)
示例:
def str(self):
return 人能看懂的字符串
# 没有重写str和repr方法前调用str方法
class MyNumber:
def __init__(self, value):
self.data = value
n1 = MyNumber(100)
print(str(n1)) # 调用object的str方法
print(repr(n1)) # 调用object的repr方法
# 打印出如下结果
# <__main__.MyNumber object at 0x10d9f0668>
# <__main__.MyNumber object at 0x10d9f0668>
# 重写str和repr方法
class MyNumber:
def __init__(self, value):
self.data = value
def __str__(self):
return "数字:%d" % self.data
def __repr__(self):
return 'MyNumber(%d)' % self.data
n1 = MyNumber(100)
print(str(n1)) # 数字:100
print(repr(n1)) # MyNumber(100)
n2 = eval("MyNumber(100)")
print(n2) # 数字:100
说明:
(1) str(obj)函数优先调用obj.str()方法返回字符串
(2) 如果obj没有__str__()方法,则调用obj.repr()方法返回的字符串
(3) 如果obj没有__repr__()方法,则调用object类的__repr__()实例方法显示格式的字符串
complex(self): complex(obj) 函数调用
int(self): int(obj) 函数调用
float(self): float(obj) 函数调用
bool(self): bool(obj) 函数调用
示例:
# 此示例示意自定义的类MyNumber能够转为数字值类型
class MyNumber:
def __init__(self, v):
self.data = v
def __repr__(self):
return "MyNumber(%d)" % self.data
def __int__(self):
'''此方法用于int(obj)函数重载,必须返回整数
此方法通常用于制订自定义对象如何转为整数的规则'''
return 10000
n1 = MyNumber(100)
print(type(n1)) #
n = int(n1)
print(type(n)) #
abs abs(obj)
len len(obj)
reversed reversed(obj)
round round(obj)
示例:
# 自定义一个MyList类,与系统内建的类一样,用来保存有先后顺序关系的数据
class MyList:
'''自定义列表类'''
def __init__(self, iterator=[]):
self.data = [x for x in iterator]
def __repr__(self):
return "MyList(%r)" % self.data
def __abs__(self):
#return MyList([abs(x) for x in self.data])
# 也可以用生成器表达式来生成
return MyList((abs(x) for x in self.data))
def __len__(self):
return len(self.data)
myl = MyList([1, -2, 3, -4])
print(myl)
print(abs(myl))
myl2 = MyList(range(10))
print(myl2)
print('myl2 的长度是:', len(myl2))
print('myl 的长度是:', len(myl))
格式:def bool(self):
…
作用:用于bool(obj)函数取值;
用于if语句真值表达式中
用于while语句真值表达式中
说明:(1) 优先调用__bool__()方法取值
(2) 如果不存在__bool__()方法,则用__len__()方法取值后判断是否为零值,如果不为零返回True,否则返回False
(3) 如果再没有__len__()方法,则直接返回True
示例:
# 自定义一个MyList类,与系统内建的类一样,用来保存有先后顺序关系的数据
class MyList:
'''自定义列表类'''
def __init__(self, iterator=[]):
self.data = [x for x in iterator]
def __repr__(self):
return "MyList(%r)" % self.data
def __abs__(self):
#return MyList([abs(x) for x in self.data])
# 也可以用生成器表达式来生成
return MyList((abs(x) for x in self.data))
# def __len__(self):
# return len(self.data)
def __bool__(self):
return False
myl = MyList([1, -2, 3, -4])
print(bool(myl)) # 没有bool方法就用len方法,不为0返回真;没有len时永远返回真;如果有bool方法,优先调用bool方法
if myl:
print("myl 是真值")
else:
print("myl 是假值")