面向对象三大特征:封装、继承、多态
封装
- 一般封装的属性前面会带有两个下划线
例:
class Student:
def __init__(self,name,age):
self.name=name
self.__age=age#年龄不希望在类的外部被使用,所以前面加了两个下划线
def show(self):
print(self.name,self.__age)
stu=Student('张三',20)
stu.show()
#在类的外部使用name和age
print(stu.name)
print(stu._Student__age)#在类的外部可以通过 _类名__封装属性 进行访问
结果:
张三 20
张三
20
如果直接访问stu.__age程序会报错
继承
语法格式:
class 子类类名(父类1,父类2…):
(缩进)pass
- 如果一个类没有继承任何类,则默认继承object
- Python支持多继承
- 定义子类时,必须在其构造函数中调用父类的构造函数
例:
class Person(object):#person继承object类
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print( self.name,self.age)
class student(Person):
def __init__(self,name,age,stu_no):
super().__init__(name,age)#super()继承父类的name、age
self.stu_no=stu_no
class teacher(Person):
def __init__(self,name,age,teacherfyear):
super().__init__(name,age)
self.teacherfyear=teacherfyear
stu=student('zz',18,5)
t=teacher('ss',34,10)
stu.info()
t.info()
结果:
zz 18
ss 34
方法重写
- 如果子类对继承自父类的某个属性或方法不满意,可以在子类中对其进行重写编写
- 子类重写后的方法中可以通过super().xxx()调用父类中被重写的方法
例:
class Person(object):#person继承object类
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print( self.name,self.age)
class student(Person):
def __init__(self,name,age,stu_no):
super().__init__(name,age)#super()继承父类的name、age
self.stu_no=stu_no
def info(self):#方法重写
super().info()#先提供父类当中的info(),在调用子类当中的输出
print('学号为:',self.stu_no)
stu=student('zz',18,5)
stu.info()
结果:
zz 18
学号为: 5
object类
:
- object类是所有类的子类,因此所有类都有object类的属性和方法
- 内置函数dir()可以查看指定对象的所有属性
- Object有一个__str__()方法,用于返回一个对于“对象的描述”,对应于内置函数str()经常
- 用于print()方法,帮我们查看对象的信息,所以我们经常会对__str__()进行重写
例:
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):#重写str的方法,用于描述
return '我的名字是{0},今年{1}岁'.format(self.name,self.age)
stu=Student('张三',20)
print(dir(stu))#查看stu所具有的属性
print(stu)
结果:
[‘class’, ‘delattr’, ‘dict’, ‘dir’, ‘doc’,‘eq’, ‘format’, ‘ge’, ‘getattribute’, ‘gt’,‘hash’, ‘init’, ‘init_subclass’, ‘le’, ‘lt’,‘module’, ‘ne’, ‘new’, ‘reduce’, ‘reduce_ex’, ‘repr’, ‘setattr’, ‘sizeof’, ‘str’, ‘subclasshook’, ‘weakref’, ‘age’, ‘name’]
我的名字是张三,今年20岁
多态
- 简单的说,多态就是“具有多种形态”,它指的是:即便不知道一个变量所引用的对象到底是什么类型,
- 仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法
例:
class Animal:
def eat(self):
print('动物能吃')
class Dog(Animal):
def eat(self):
print('狗吃骨头...')
class cat(Animal):
def eat(self):
print('猫吃鱼...')
class person:
def eat(self):
print('人吃五谷杂粮')
def fun(obj):#定义一个函数
obj.eat()
fun(cat())
fun(Dog())
fun(Animal())
fun(person())
结果:
猫吃鱼…
狗吃骨头…
动物能吃
人吃五谷杂粮
特殊方法和特殊属性(全部是双下划线)
特殊属性:
- dict:获得类对象或实例对象所绑定的所有属性和方法的字典
例:
class A:
pass
class B:
pass
class C(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
x=C('jack',20)
print(x.__dict__)#实例对象的属性字典
print(C.__dict__)#类对象的属性字典
print(x.__class__)#输出实例对象所属的类
print(C.__bases__)#类的所有基类
print(C.__base__)#类的第一个基类
print(C.__mro__)#输出的是类层次结构
print(A.__subclasses__())#子类的列表
结果:
{‘name’: ‘jack’, ‘age’: 20}
{‘module’: ‘main’, ‘init’: <function C.init at
0x000001DF7D02CD30>, ‘doc’: None}<class ‘main.C’>
(<class ‘main.A’>, <class ‘main.B’>)
<class ‘main.A’>
(<class ‘main.C’>, <class ‘main.A’>, <class ‘main.B’>,<class ‘object’>)
[<class ‘main.C’>]
特殊方法(有括号):
- len():通过重写__len__()方法,让内置函数len()的参数可以是自定义类型
- add():通过重写__add__()方法,可使用自定义对象具有“+”功能
例:
class Student:
def __init__(self,name):
self.name=name
def __add__(self,other):#实现了两个对象的加法运算
return self.name+other.name
def __len__(self):
return len(self.name)
stu1=Student('张三')
stu2=Student('李四')
s=stu1+stu2#如果没有def __add__(self,other)函数输出结果s会报错
print(s)
m=stu1.__add__(stu2)#让两个对象相加的第二种写法
print(m)
print(len(stu1))#没有def __len__方法的话,会报错
print(stu1.__len__())#第二种得到对象长度的方法
结果:
张三李四
张三李四
2
2
- new():用于创建对象
- init():对创建的对象进行初始化
- new()方法在__init__方法执行之前先进行创建对象
类的赋值
只是形成两个变量,实际上还是指向同一个对象
例:
class CPU:
pass
cpu1=CPU()
cpu2=cpu1
print(cpu1)
print(cpu2)#cpu1与cpu2内存地址相同
结果:
<__main__.CPU object at 0x000001D3677DCFA0>
<__main__.CPU object at 0x000001D3677DCFA0>
(此时两个变量的内存地址为同一个)