Python的学习(十四):面向对象
面向对象三大特征
封装
提高程序的安全性。
-
将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法,这样不需要关心内部具体实现细节,从而隔离了复杂度。
class Car: def __init__(self,brand): self.brand = brand def start(self): print('汽车已经启动。。。') car = Car('宝马X5') car.start() print(car.brand)
-
在Python中没有专门修饰符用于属性的私有,如果希望属性不在类外部被访问,前面使用两个“_”
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() #在类的外部不能直接使用age属性 #查看类的所有属性 print(dir(stu)) #可以通过_Student__age访问 print(stu._Student__age) #不建议访问
继承
提高代码的复用性。
语法格式:
class 子类类名(父类1,父类2.....):
pass
python支持多继承!!!!!!!!!!
如果一个类没有继承任何类,那么默认继承Object类。
定义子类时,必须在其构造函数中调用父类的构造函数。
#定义一个父类
class 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)
self.stu_no = stu_no
#定义一个老师子类
class Teacher(Person):
def __init__(self,name,age,teachofyear):
super().__init__(name,age)
self.teachofyear = teachofyear
#使用
stu = Student('张三',20,'1001')
teacher = Teacher('李四',34,10)
#可以多继承
class A:
pass
class B:
pass
class C(A,B):
pass
方法重写
- 如果子类对继承父类的某个属性或者方法不满意,可以在子类种对其(方法体)进行重新编写
- 子类重新编写的方法可以通过**super().xxx()**调用父类中被重写的方法。
class Student(Person):
def __init__(self,name,age,stu_no):
super().__init__(name,age)
self.stu_no = stu_no
#重写info方法
def info(self):
#调用父类的方法
super().info()
print('学号:{0}'.format(self.score))
object类
- object类是所有类的父类,因此所有类都有object类的属性和方法。
- 内置函数dir()可以查看指定对象所有的属性
-
Object有一个_
str_
()方法,可以用于返回一个对于对象的描述对应与内置函数str()经常用于·print()方法,帮我们查看对象信息,所以我们经常会对_str_()重写。
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def info(self):
print('姓名:{0},年龄:{1}'.format(self.name,self.age))
#重写方法后不再输出内存地址,而是输出重写后的函数内容
def __str__(self):
return '姓名:{0},年龄:{1}'.format(self.name,self.age)
o = object()
p = Person('jack',20)
print(dir(o))
print(dir(p))
print(p)
多态
提高程序的可拓展性和可维护性!
具有多种形态,指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量引用的类型,动态决定调用哪个对象的方法。
class Animal(object):
def eat(self):
print('动物会吃')
class Dog(Animal):
def eat(self):
print('狗吃骨头')
class Cat(Animal):
def eat(self):
print('猫吃鱼儿')
class Person(object):
def eat(self):
print('人吃好吃的')
#创建一个函数
def fun(obj):
obj.eat()
#调用
fun(Cat())#猫吃鱼儿
fun(Dog())#狗吃骨头
fun(Person())#人吃好吃的
多态的区别
-
静态语言实现多态的三个必要条件
- 继承
- 方法重写
- 父类引用指向子类对象
-
动态语言不需要关心对象是什么类型,只关心对象的行为
特殊的属性和方法
特殊属性
- __dict__ :获得类对象或者实例对象所绑定的所有属性和类方法的字典。
class A:
pass
class B:
pass
class C(A,B):
def __init__(self,name,age):
self.name = name
self.age = age
class D(A):
pass
#创建C类的对象
c = C('Jack',20)#c是一个实例对象
print(c.__dict__)#实例对象的属性字典
print(C.__dict__)
print('----------')
print(c.__class__)#输出对象所属的类
print(C.__bases__)#C类的父类类型的元素
print(C.__base__)#离得近的父类,第一个,基类
print(C.__mro__)#类的层次结构
print(A.__subclasses__())#子类的列表
特殊方法
名称 | 描述 |
---|---|
__len__() | 通过重写,让内置函数len的参数可以是自定义类型 |
__add__() | 通过重写,可以使用自定义对象具有“+”功能 |
__new__() | 用于创建对象 |
__init__() | 对创建的对象进行初始化 |
#add方法
a = 20
b = 100
c = a + b #两个整数可以进行相加操作
print(c)#120
d = a.__add__(b)
print(d)#120
#两个结果一致
class Student:
def __init__(self,name):
self.name = name
stu1 = Student('张三')
stu2 = Student('李四')
s = stu1 + stu2
print(s)#会报错,因为两个类型不能相加
#要是非要相加,可以重写add函数
def __add__(self,other):
return self.name + other.name
s = stu1.__add__(stu2)#结果和上面的相加操作一样是:张三李四
print(s)
#len方法
print('---------------')
lst = [11,22,33]
print(len(lst))
print(lst.__len__())
#两个函数的输出结果都是相同的为3
print(len(stu1))#报错,因为该对象没有长度1
#非要输出长度,重写方法
def __len__(self):
return len(self.name)
- new和init
class Person(object):
#创建对象
def __new__(cls,*args,**kwargs):
print('__new__被调用了,cls的id值为{0}'.format(id(cls)))
obj = super().__new__(cls)
print('创建的对象id为:{0}'.format(id(obj)))
return obj
#初始化对象
def __init__(self,name,age):
print('__init__被调用了,self的id值为{0}'.format(id(self)))
self.name = name
self.age = age
#创建Person类的实例对象
p1 = Person('张三',20)
print('p1这个Person类的实例对象id是{0}'.format(id(p1)))
- 首先将Person对象传给cls,id是9360
- 然后将cls传到new函数中创建一个obj对象,id是7104
- 将obj对象返回给self,id是7104
- 最后将self初始化后传给p1,id还是7104
类的浅拷贝和深拷贝
变量的赋值
- 只是形成两个变量,实际上还是指向同一个对象
class CPU:
pass
class Disk:
pass
class Computer:
def __init__(self,cpu,disk):
self.cpu = cpu
self.disk = disk
#变量的赋值
cpu1 = CPU()
cpu2 = cpu1
print(cpu1)
print(cpu2)#两个内存地址是一样的
实质上是同一个对象赋值给了两个变量:
浅拷贝
- 一般python中的拷贝都是浅拷贝,拷贝时对象包含的子对象内容不拷贝,因此,源对象和拷贝对象会引用同一个子对象。
#类的创建见上面
disk = Disk()#创建一个硬盘类对象
computer = Computer(cpu1,disk)#创建一个计算机类对象
#浅拷贝
import copy
computer2 = copy.copy(computer)
print(computer,computer.cpu,computer.disk)
print(computer2,computer2.cpu,computer3.disk)
#不是相同的对象,但是子对象是相同的
内存解释:
深拷贝
- 使用deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象的子对象也不相同
computer3 = copy.deepcopy(commputer)
print(computer,computer.cpu,computer.disk)
print(computer3,computer3.cpu,computer3.disk)
内存解释:
总结
版权声明:本文为weixin_51276056原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。