文章目录
1. 类与对象
类的组成
类属性: 直接定义在类中,方法外的变量
实例属性: 定义在__init__方法中,使用self打点的变量
实例方法:定义在类中的函数,而且自带参数self
静态方法:使用装饰器@staticmethod修饰的方法
类方法:使用装饰器@classmethod修饰的方法
class Student:
school="北京二中"
# 初始化方法
def __init__(self,name,age):
self.name=name
self.age=age
# 定义在类中的函数,称为方法,自带一个参数self
def show(self):
print(self.name,self.age)
# 静态方法
@staticmethod
def testStaticMethod():
print('这是一个静态方法,不能调用实例属性,也不能调用实例方法')
@classmethod
def testClassMethod(cls):
print('这是一个类方法,不能调用实例属性,也不能调用实例方法')
stu=Student('name',18)
# 类属性,直接使用类名,打点调用
print(Student.school)
# 实例属性,直接使用对象名打点调用
print(stu.name,stu.age)
# 实例方法,使用对象名打点调用
stu.show()
# 类方法,@classmethod 进行修饰的方法,直接使用类名打点调用
Student.testClassMethod()
# 静态方法,@staticmethod 进行修饰的方法,直接使用类名打点调用
Student.testStaticMethod()
输出
北京二中
name 18
name 18
这是一个类方法,不能调用实例属性,也不能调用实例方法
这是一个静态方法,不能调用实例属性,也不能调用实例方法
动态绑定属性和方法
class Student:
school="北京二中"
# 初始化方法
def __init__(self,name,age):
self.name=name
self.age=age
# 定义在类中的函数,称为方法,自带一个参数self
def show(self):
print(self.name,self.age)
stu1=Student('小红',18)
stu2=Student('小梅',19)
# 为stu2动态绑定一个属性
stu2.gender='女'
print(stu2.gender)
def study():
print('这是一个外部的方法')
stu2.fun=study # 函数的一个赋值
# 调用
stu2.fun()
输出
女
这是一个外部的方法
2. 权限控制
是通过对属性或方法添加单下划线、双下划线以及首尾双下划线来实现的
(1)单下划线开头
以单下划线开头的属性或方法表示protected受保护的成员,这类成员被视为仅供内部使用,允许类本身和子类进行访问,但实际上它可以被外部代码访问
(2)双下划线开头
表示private私有的成员,这类成员只允许定义该属性或方法的类本身进行访问
(3)首尾双下划线
一般表示特殊的方法
class Person():
def __init__(self,name,age,gender):
self._name=name # 受保搞的,只能本类和子类才能访问
self.__age=age # 表示私有的,只能类本身去访问
self.gender=gender # 普通实例属性,类内部、外部及子类都可以访问
def _fun1(self):
print('类本身、子类可以访问')
def __fun2(self):
print('只有定义内的类可以访问')
def show(self): # 普通的实例方法
self._fun1() # 类本身访问受保护的方法
self.__fun2() # 类本身访问私有方法
print(self._name) # 受保搞的实例属性
print(self.__age) # 私有的实例属性
(4)私有的实例属性或者方法的访问方法
person=Person('韩梅梅','12','女')
print(person._Person__age)
person._Person__fun2()
输出
12
只有定义内的类可以访问
print(dir(person))
输出
[‘_Person__age’, ‘_Person__fun2’, ‘class’, ‘delattr’, ‘dict’, ‘dir’, ‘doc’, ‘eq’, ‘format’, ‘ge’, ‘getattribute’, ‘getstate’, ‘gt’, ‘hash’, ‘init’, ‘init_subclass’, ‘le’, ‘lt’, ‘module’, ‘ne’, ‘new’, ‘reduce’, ‘reduce_ex’, ‘repr’, ‘setattr’, ‘sizeof’, ‘str’, ‘subclasshook’, ‘weakref’, ‘_fun1’, ‘_name’, ‘gender’, ‘show’]
实际上这样调用的方法是不推荐的
3. 私有属性的get,set封装
(1)get 读取
使用@property 修饰方法,将方法转成属性使用
class Person():
def __init__(self,name,age,gender):
self.name=name # 受保搞的,只能本类和子类才能访问
self.__age=age # 表示私有的,只能类本身去访问
self.gender=gender # 普通实例属性,类内部、外部及子类都可以访问
# 使用 @property 修饰方法,将方法转成属性使用
@property
def age(self):
return self.__age
person=Person('韩梅梅','12','女')
print(person.age)
输出:
12
set 写入
class Person():
def __init__(self,name,age,gender):
self.name=name # 受保搞的,只能本类和子类才能访问
self.__age=age # 表示私有的,只能类本身去访问
self.gender=gender # 普通实例属性,类内部、外部及子类都可以访问
# 使用 @property 修饰方法,将方法转成属性使用
@property
def age(self):
return self.__age
@age.setter
def age(self,value):
self.__age=value
person=Person('韩梅梅','12','女')
person.age=13
print(person.age)
输出
13
4. 继承
在python中,一个父类可以有n多个子类,一个子类也可以拥有N多个父类,如果一个类没有继承 任何类,那么这个类默认继承的是object类
class Person:
def __init__(self, name,age):
self.name = name
self.age = age
def show(self):
print(f'我是{self.name},我{self.age}岁了')
# Student继承Person
class Student(Person):
def __init__(self,name,age,stuno):
super().__init__(name,age) # 调用父类的初始化方法
self.stuno = stuno
class Teacher(Person):
def __init__(self,name,age,course):
super().__init__(name,age)
self.course = course
stu=Student('韩梅梅',15,'s2021001')
teacher=Teacher('李老师',15,'英语')
(1)多继承
class FatherA():
def __init__(self,name):
self.name=name
def showA(self):
print("FatherA:",self.name)
class FatherB():
def __init__(self, age):
self.age = age
def showB(self):
print("FatherB:", self.age)
class Son(FatherA,FatherB):
def __init__(self,name,age,gander):
# 需要调用两个父类的初始化方法
FatherA.__init__(self,name)
FatherB.__init__(self,age)
self.gander = gander
son=Son('李磊',20,'男')
son.showA()
son.showB()
输出
FatherA: 李磊
FatherB: 20
5.方法重写
(1)子类继承了父类就拥有了父类中公有成员和受保护的成员
(2)父类的方法法并不能完全适合子类的需要求这个时候子类就可以重写父类的方法子类在重新父类的方法时,要求方(3)法的名称必须与父类方法的名称相同,在子类重写后的方法中可以通过super().xxx()调用父类中的方法
class Person:
def __init__(self, name,age):
self.name = name
self.age = age
def show(self):
print(f'我是{self.name},我{self.age}岁了')
# Student继承Person
class Student(Person):
def __init__(self,name,age,stuno):
super().__init__(name,age) # 调用父类的初始化方法
self.stuno = stuno
def show(self):
# 调用父类中的方法
# super().show()
print(f'我是{self.name},我{self.age}岁,我的学号是{self.stuno}')
class Teacher(Person):
def __init__(self,name,age,course):
super().__init__(name,age)
self.course = course
def show(self):
# 调用父类中的方法
super().show()
print(f'我教的是{self.course}课程')
stu=Student('韩梅梅',15,'s2021001')
teacher=Teacher('李老师',15,'英语')
stu.show()
teacher.show()
输出
我是韩梅梅,我15岁,我的学号是s2021001
我是李老师,我15岁了
我教的是英语课程
6.多态
(1)指的就是“多种形态”,即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用对象的方法,
(2)在程序运行过程中根据变量所引用对象的数据类型,动态决定调用哪个对象中的方法。
(3)Python语言中的多态,根本不关心对象的数据类型,也不关心类之间是否存在继承关系,只关心对象的行为(方法)。只要不同的类中有同名的方法,即可实现多态
class Person():
def eat(self):
print('人吃五谷杂粮')
class Cat():
def eat(self):
print('猫喜欢吃鱼')
class Dog():
def eat(self):
print('狗喜欢啃骨头')
# 这三个类中都有一个同名方法,eat
# 编写函数
def fun(obj):
obj.eat()
# 分别创建三个对象
person = Person()
cat = Cat()
dog = Dog()
# 调用fun函数
# 在python中的多态,不关心对象的数据类型,只关心对象是否上有同名方法
fun(person)
fun(cat)
fun(dog)
输出
人吃五谷杂粮
猫喜欢吃鱼
狗喜欢啃骨头
7. object类
所有的类直接或间接的父类,所有类都拥有object类的属性和方法
object类中特殊的方法 | 功能描述 |
---|---|
__new__() | 由系统调用,用于创建对象 |
__init__() | 创建对象时手动调用,用于初始化对象属性值 |
__str__() | 对象的描述,返回值是str类型,默认输出内存地址 |
特殊方法
运算符 | 特殊方法 | 功能描述 |
---|---|---|
+ | __add__() | 加法运算 |
- | __sub__() | 减法运算 |
<,<=,== | __lt__(),__le__(),__eq__() | 比较运算 |
>,>=,!= | __gt__(),__ge__(),__ne__() | 比较运算 |
*,/ | __mul__(),__truediv__() | 乘法运算,非整除运算 |
%,// | __mod__(),__floordiv__() | 取余运算,整除运算 |
** | __pow__() | 幂运算 |
特殊属性
特殊属性 | 功能描述 |
---|---|
obj.__dict__ | 对象的属性字典 |
obj.__class__ | 对象所属的类 |
obj.__bases__ | 类的父类元组 |
obj.__base__ | 类的父类 |
obj.__mro__ | 类的层次结构 |
obj._subclasses__() | 类的子类列表 |
class FatherA():
def __init__(self,name):
self.name=name
def showA(self):
print("FatherA:",self.name)
class FatherB():
def __init__(self, age):
self.age = age
def showB(self):
print("FatherB:", self.age)
class Son(FatherA,FatherB):
def __init__(self,name,age,gander):
# 需要调用两个父类的初始化方法
FatherA.__init__(self,name)
FatherB.__init__(self,age)
self.gander = gander
a=FatherA('fathera')
b=FatherB(50)
son=Son('李磊',20,'男')
print('对象a的属性字典',a.__dict__)
print('对象b的属性字典',b.__dict__)
print('对象son的属性字典',son.__dict__)
print('对象a的所属的类',a.__class__)
print('对象b的所属的类',b.__class__)
print('对象son的所属的类',son.__class__)
print('FatherA类的父类元组',FatherA.__bases__)
print('FatherB类的父类元组',FatherB.__bases__)
print('Son类的父类元组',Son.__bases__)
print('FatherA类的父类',FatherA.__base__)
print('FatherB类的父类',FatherB.__base__)
print('Son类的父类',Son.__base__)
print('FatherA类的层次结构',FatherA.__mro__)
print('FatherB类的层次结构',FatherB.__mro__)
print('Son类的层次结构',Son.__mro__)
print('FatherA类的子类列表',FatherA.__subclasses__())
print('FatherB类的子类列表',FatherB.__subclasses__())
print('Son类的子类列表',Son.__subclasses__())
输出
对象a的属性字典 {‘name’: ‘fathera’}
对象b的属性字典 {‘age’: 50}
对象son的属性字典 {‘name’: ‘李磊’, ‘age’: 20, ‘gander’: ‘男’}
对象a的所属的类 <class ‘main.FatherA’>
对象b的所属的类 <class ‘main.FatherB’>
对象son的所属的类 <class ‘main.Son’>
FatherA类的父类元组 (<class ‘object’>,)
FatherB类的父类元组 (<class ‘object’>,)
Son类的父类元组 (<class ‘main.FatherA’>, <class ‘main.FatherB’>)
FatherA类的父类 <class ‘object’>
FatherB类的父类 <class ‘object’>
Son类的父类 <class ‘main.FatherA’>
FatherA类的层次结构 (<class ‘main.FatherA’>, <class ‘object’>)
FatherB类的层次结构 (<class ‘main.FatherB’>, <class ‘object’>)
Son类的层次结构 (<class ‘main.Son’>, <class ‘main.FatherA’>, <class ‘main.FatherB’>, <class ‘object’>)
FatherA类的子类列表 [<class ‘main.Son’>]
FatherB类的子类列表 [<class ‘main.Son’>]
Son类的子类列表 []
8. 类的深拷贝与浅拷贝
拷贝时,对象包含的子对象内容不拷贝,因此源对象与拷贝对象会引用同一个子对象
使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象源对象和拷贝对象所有的子对象也不相同
# 发动机
class Engine():
pass
# 变速箱
class Gearbox():
pass
class Car():
def __init__(self,engine,gearbox):
self.engine = engine
self.gearbox = gearbox
engine = Engine()
gearbox = Gearbox()
car = Car(engine,gearbox)
print(car,'car子对象',car.engine,car.gearbox)
import copy
car2=copy.copy(car)
car3=copy.deepcopy(car)
print(car2,'car2子对象',car2.engine,car2.gearbox)
print(car3,'car3子对象',car3.engine,car3.gearbox)
输出
<main.Car object at 0x00000287F0D919D0>car子对象 <main.Engine object at 0x00000287F0D91A30> <main.Gearbox object at 0x00000287F0D919A0>
<main.Car object at 0x00000287F0D91B20> car2子对象 <main.Engine object at 0x00000287F0D91A30> <main.Gearbox object at 0x00000287F0D919A0>
<main.Car object at 0x00000287F0D92B10> car3子对象 <main.Engine object at 0x00000287F0DC0530> <main.Gearbox object at 0x00000287F0DC0590>