python面向对象
一.相关定义
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
二.类
相关知识:
1.基本形式
class 类名:
"""注释"""
类体
2.类规范:首字母大写
3.类名加. 调用属性和方法
4.方法
- dir(类):查看属性和方法,返回一个列表
- 类名.__dict__:查看属性可方法,返回键值对
- __name__:查看类名
- __doc__:文档信息,不能被继承,没有返回None
- __base__:查看继承于哪个类
- __module__:查看来自于哪个模块
- __class__:查看哪个类来的类由type来
三.实例
1.实例=类名() --》生产实例
2.__init__初始化,在产生实例的过程中会执行类的 __init__方法
3.实例也可以通过 . 访问类的属性
4.__dict__中 实例只绑定了属性,没有绑定方法,通过 . 访问类的方法执行
5.self相当于实例本身,定义方式中的(self),全部相当于把实例传入进去
实例.方法() <==>类.方法(实例)
1 class Dog(): # 定义Dog类,首字母大写 2 """ 3 定义Dog类 4 """ 5 6 def __init__(self, name, type): 7 self.name = name 8 self.type = type 9 10 def eat(self): 11 print('%s在吃东西' % self.name) 12 13 def run(self): 14 print('%s在奔跑' % self.name) 15 16 17 d = Dog('pp', '柯基') # 实例化Dog 18 print(d.name) 19 print(d.type) 20 d.eat() 21 d.run() 22 print(d.__dir__()) # 查看全部属性和内置方法 23 print(d.__dict__) # 查看属性,返回键值对,实例只绑定了属性,没有绑定方法,通过 . 访问类的方法执行 24 print("---------------------------") 25 print(Dog.__dict__) # 查看类的属性和方法,返回键值对 26 print(dir(Dog)) # 查看类的属性和方法,返回列表 27 print(Dog.__name__) # 查看类名 28 print(Dog.__doc__) # 查看文档 29 print(Dog.__module__) # 查看来自哪个模块 30 print(Dog.__base__) # 查看继承于哪个类 31 print(Dog.__class__) # 查看由哪个类来的,元类是type
结果
1 pp 2 柯基 3 pp在吃东西 4 pp在奔跑 5 ['name', 'type', '__module__', '__doc__', '__init__', 'eat', 'run', '__dict__', '__weakref__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__'] 6 {'name': 'pp', 'type': '柯基'} 7 --------------------------- 8 {'__module__': '__main__', '__doc__': '\n 定义Dog类\n ', '__init__': <function Dog.__init__ at 0x0000023A817B5378>, 'eat': <function Dog.eat at 0x0000023A8285E158>, 'run': <function Dog.run at 0x0000023A8285E1E0>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>} 9 ['__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__', 'eat', 'run'] 10 Dog 11 12 定义Dog类 13 14 __main__ 15 <class 'object'> 16 <class 'type'>
四.类和实例的增删改查
类
1 class Dog(): # 定义Dog类,首字母大写 2 x = 1 3 4 def __init__(self, name, type): 5 self.name = name 6 self.type = type 7 8 def eat(self): 9 print('%s在吃东西' % self.name) 10 11 def run(self): 12 print('%s在跑' % self.name) 13 14 15 d = Dog('xiaohong', '柯基') 16 Dog.eat(d) # 当调用类方法时需要手动传入实例对象,等价于d.eat() 17 18 Dog.y = 2 # 增加属性 19 Dog.x = 10 # 修改类属性 20 21 def eat(self): 22 print('修改后-->%s在吃' % self.name) 23 24 25 Dog.eat = eat # 修改类方法 26 print(Dog.__dict__) 27 d.eat() 28 del Dog.y # 删除类属性
实例
1 d.y = 20 # 增加属性,加入的是实例的__dict__字典,与类无关 2 3 4 def sleep(self): # 可以自定义实例的方法,但是注意要穿入参数,当调用类的方法时,会自动将实例传入self中 5 print('%s正在睡觉' % self.name) 6 7 8 d.sleep = sleep # 增加实例方法 9 del d.y # 删除实例属性 10 d.sleep(d) # 注意此时需要传入self参数 11 d.x=100 # 修改属性,不影响Dog的x的值 12 print(d.__dict__) 13 print(Dog.__dict__)
1 xiaohong正在睡觉 2 {'name': 'xiaohong', 'type': '柯基', 'sleep': <function sleep at 0x000002102FB8C1E0>, 'x': 100} 3 {'__module__': '__main__', 'x': 1, '__init__': <function Dog.__init__ at 0x00000210319B5378>, 'eat': <function Dog.eat at 0x0000021032A4E158>, 'run': <function Dog.run at 0x0000021032A4E1E0>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None}
五.类的相关装饰器和组合
静态属性 @property
类方法 @classmethod
静态方法 @staticmethod
1 class Room: 2 def __init__(self, name, length, width, height): 3 self.name = name 4 self.length = length 5 self.width = width 6 self.height = height 7 8 @property # 对于函数属性,可以不同加括号,相当于把函数属性转换成静态属性 9 def area(self): 10 res = self.length * self.width 11 print('面积是%s' % res) 12 return res 13 14 @classmethod # 类方法,不必要传入实例的属性,即不用传入self 15 def tell_info(cls, place): # 类和实例都可以调用,cls均不需要传入,系统默认将类传入cls 16 print(cls) 17 print('这是一个房子,位于%s' % place) 18 19 @staticmethod # 静态方法,与类和实例属性均无关,无法访问类和实例属性 20 def happy(who, what): # 类和实例均能调用 21 print('%s在房子里干%s,很高兴' % (who, what)) 22 23 24 r = Room('客厅', 3, 4, 5) 25 print(r.area) 26 r.tell_info('浙江') 27 Room.tell_info('浙江') 28 Room.happy('ppp', 'sing_song') 29 r.happy('ppp', 'sing_song')
1 面积是12 2 12 3 <class '__main__.Room'> 4 这是一个房子,位于浙江 5 <class '__main__.Room'> 6 这是一个房子,位于浙江 7 ppp在房子里干sing_song,很高兴 8 ppp在房子里干sing_song,很高兴
组合
大类包含小类
把类的实例化放到一个新类里
self.foot=Foot()
1 class Fish: 2 def __init__(self, type): 3 self.type = type 4 5 def swim(self): 6 print('小鱼在快乐的游泳') 7 8 9 class Turtle: 10 pass 11 12 13 class Pool: 14 def __init__(self, f_num, t_num): 15 self.f_num = f_num 16 self.t_num = t_num 17 self.fish = Fish('鲫鱼') 18 self.turtle = Turtle() 19 20 def swim(self): 21 print('池塘里有%s只鱼,鱼的类型是%s,%s只乌龟' % (self.f_num, self.fish.type, self.t_num)) 22 23 24 p = Pool(10, 3) 25 p.swim() 26 # 池塘里有10只鱼,鱼的类型是鲫鱼,3只乌龟
六.三大特性
继承
分类:单继承、多继承
继承顺序:__mro__
含义
含义一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
含义二:声明某个子类兼容于某基类,定义一个接口类,子类继承接口类,并且实现接口中定义的方法
1 import abc 2 3 4 class AllFile(metaclass=abc.ABCMeta): 5 6 @abc.abstractmethod 7 def write(self): 8 pass 9 10 def read(self): 11 raise NotImplementedError("必须实现read方法") 12 13 # 子类必须写write方法 14 # 子类不写read方法,调用read报错,也需要自定义 15 class MyFile(AllFile): 16 def write(self): 17 pass 18 19 def read(self): 20 pass 21 22 23 file = MyFile() 24 file.read()
属性:1.同名子类不会覆盖父类的方法,是先从子类找,找不到去父类
2.子类.__dict__没有父类的属性,但是可以调用
3.在子类中调用父类的方法:super([子类,self]).父类方法()
多态
1.由不同的类实例化得到的对象,调用同一个方法,执行的逻辑不同
2.不同对象继承于同一父类,但是对父类同一方法有不同的响应行动
1 print('asd'.__len__()) 2 print([1,2,5,6].__len__()) 3 print({'a:1,''b':1}.__len__()) 4 5 6 class Hho: 7 def __init__(self,temp): 8 self.temp=temp 9 def state(self): 10 if self.temp<=0: 11 print('温度太低了,水结冰了') 12 if 0<self.temp<100: 13 print('温度合适,状态是水') 14 if self.temp>=100: 15 print('温度太高了,水汽化了') 16 ice=Hho(-3) 17 water=Hho(10) 18 gas=Hho(130) 19 ice.state() 20 water.state() 21 gas.state()
“开闭”原则:
- 对扩展开放(Open for extension):允许子类重写方法函数
- 对修改封闭(Closed for modification):不重写,直接继承父类方法函数
封装
1.定义:
在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其含义是其他程序无法调用。要了解封装,离不开“私有化”,就是将类或者是函数中的某些属性限制在某个区域之内,外部无法调用。
2.实现方法:
a. _ 单下划线开头:约定是内部属性,但是外部还是可以调用
b. __ 双下划线开头:外部无法直接调用,但通过 _People__star 调用 --》(_类名__变量名)
3.接口函数/访问函数:通过内部定义函数访问私有属性,外部可以通过函数访问
@property 调用者不必关系内部怎么实现的,只需要调用属性即可
1 class Foo: 2 __x = 1 3 __y = 2 4 5 def __init__(self, m, n): 6 self.__m = m 7 self.__n = n 8 9 @classmethod # 封装的函数只能在内部调用,外部不能调用,外部调用需要写成 _类名__属性名 10 def tem(cls): 11 return cls.__x * cls.__y 12 13 def temp(self): 14 return self.__m * self.__n 15 16 def __res(self): 17 return self.__x * self.__y 18 19 def res(self): 20 return self.__x * self.__y 21 22 23 f = Foo(5, 6) 24 print(f._Foo__m) 25 print(f.tem()) 26 print(f.temp()) 27 print(f.res()) 28 print(f._Foo__res())
1 5 2 2 3 30 4 2 5 2
七.反射
1.内置函数
hasattr(对象,属性):判断是否有属性
getattr(对象,属性,[设置值]):获得属性,没有设置默认值,如果没有报错,设置了,没有返回设置的值
setattr(对象,属性,value):设置属性,可以设置函数属性
delattr(对象,属性):删除属性,不能删类的属性,只能删自己的
2.补充:动态导入,通过字符串导入模块
m=__import__('m1.t')
得到的是顶级目录,m1,通过m1.t可以得到t模块
通过importlib模块,m=importlib.import_module('m1.t')
得到的是m1下的t模块
3类的内置函数
__getattr__:获取不存在的属性时执行
__getattribute__:获取属性时执行,不管存不存在都执行,不存在时抛出异常AttributeError异常,然后__getattr__执行
__setattr__:设置属性时执行,self.key=value,需要设置self.__dict__[k]=v ,如果设置self.k=v会无限递归
__delattr__:删除属性时执行,删除对象属性不存在时也执行,需要设置self.__dict__.pop(item)-->删除的是字典key和value
注意:继承基本类,重新定义函数,修改方法,注意修改时调用父类方法super(),否则会无限递归
4.授权(类似于组合)
file=open(file,mode,encoding)
通过__getattr__(-->方法不存在时调用),然后返回getatter self.file.write()得到内置文件write方法
可以重新定义 write() self.file.write() 重写write方法
1 class Foo: 2 x = 1 3 4 def res(self): 5 print('hello') 6 7 8 f = Foo() 9 print(hasattr(Foo, 'x')) 10 setattr(Foo, 'y', 7) 11 print(Foo.__dict__) 12 print(getattr(Foo, 'y', '没有想要的值')) 13 print(hasattr(f, 'x')) 14 setattr(f, 'y', 7) 15 print(f.__dict__) 16 print(getattr(f, 'y', '没有想要的值')) 17 delattr(f, 'y') 18 19 # True 20 # {'__module__': '__main__', 'x': 1, 'res': <function Foo.res at 0x0000016F23D85378>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None, 'y': 7} 21 # 7 22 # True 23 # {'y': 7} 24 # 7
八.其他知识点
1.一些内置函数
isinstance(对象,类) : 对象是否是类实例化来的,类是父类也是True
issubclass(类1,类2):类1是否是类2的子类,后面可以是元祖
2.魔法方法
__getitem__
__setitem__
__delitem__
f1['name']=‘root’ --》 以字典形式操作时调用(容器类)
3.str与repr
(return 必须是字符串类型)
__str__ --》 print()执行时调用,可以定制__str__,得到自己想要的结果
__repr__ --》 在解释器中执行是调用
print()先找__str__,找不到再找__repr__
4.执行forrmat时执行__format__,返回值是必须是字符串
可以重写定制format
5.__slots__
当一个类只有很少的属性但是有很多实例时,可以定义__slots__=['name','age']
那么__solts__就代替了__dict__,且不能再增加额外的新的属性了
6.__del__
a.只有实例删除的时候会删除
b.程序运行完成时内存释放会回收实例,执行__del__
7.__call__
后面加括号,触发执行
8.__iter__
只有有这个方法才能转换成迭代器对象,返回可迭代对象
9.__next__
设置next的返回值,定义错误raise StopIteration('终止了')
10.上下文管理协议
__enter__:with 运行时执行
__exit__:with代码块执行完后执行