面向对象
Posted accolade
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象相关的知识,希望对你有一定的参考价值。
类
类,就是一种事物,具有共性。比如dict,人,熊猫
对象,类的实例化后所产生的,具有个性,比如{1:‘vf’},春哥,团团。
申明类:
class 类名: ‘类的文档字符串‘#类的静态属性
def __init__(self,参数)
实例化所需要的参数代码
def 功能
面向对象小结——定义及调用的固定模式
class 类名: def __init__(self,参数1,参数2): self.对象的属性1 = 参数1 self.对象的属性2 = 参数2 def 方法名(self):pass def 方法名2(self):pass 对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西 #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法 #括号里传参数,参数不需要传self,其他与init中的形参一一对应 #结果返回一个对象 对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 即可 对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
我们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
class Person: country = ‘China‘ def __init__(self,name,sex,age,hobby): self.name=name self.sex=sex self.age=age self.hobby=hobby def func(self): print(dir(self)) p1=Person(‘alex‘,‘male‘,68,‘study‘) print(dir(Person)) print(dir(p1)) print(p1.__dict__) print(Person.__name__) print(Person.__doc__) print(Person.__base__) print(Person.__bases__) print(Person.__module__) print(Person.__class__) print(Person.__dict__) #输出的结果为 ‘‘‘
[‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__le__‘, ‘__lt__‘, ‘__module__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘country‘, ‘func‘] [‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__le__‘, ‘__lt__‘, ‘__module__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘age‘, ‘country‘, ‘func‘, ‘hobby‘, ‘name‘, ‘sex‘] {‘hobby‘: ‘study‘, ‘sex‘: ‘male‘, ‘name‘: ‘alex‘, ‘age‘: 68} Person None <class ‘object‘> (<class ‘object‘>,) __main__ <class ‘type‘> {‘__init__‘: <function Person.__init__ at 0x0000000000832620>, ‘country‘: ‘China‘, ‘__doc__‘: None, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Person‘ objects>, ‘__module__‘: ‘__main__‘, ‘func‘: <function Person.func at 0x00000000008326A8>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Person‘ objects>} ‘‘‘
面向对象的组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
面向对象的命名空间
class name_space: code=‘utf-8‘ def __init__(self,name,sex,age): self.name=name self.age=age self.sex=sex lhy=name_space(‘lhy‘,‘female‘,18) dxx=name_space(‘dxx‘,‘male‘,23) print(name_space.code)#utf-8 print(lhy.code)#utf-8 print(lhy.age)#18 #print(name_space.name)#报错 #name_space.__dict__[‘code‘]=‘unicode‘#报错 name_space.code=‘unicode‘ print(name_space.code)#unicode print(lhy.code)#unicode lhy.__dict__[‘code‘]=‘gbk‘ print(lhy.__dict__)#gbk print(lhy.code)#gbk print(name_space.code)#unicode
lhy.__dict__.pop(‘code‘)#删除code
print(lhy.code)#unicode
类的静态变量是可以通过 类.属性名来改变的,但是不可以通过类.__dict__来进行改变。同时静态属性的改变影响对象的静态属性,应为这个属性是绑定在类中并指向一个内存地址的
对象,可也以改变静态属性的。对象名.属性来改变,但是不会影响其他对象以及类的这静态属性的,相当于自己在自己的命名空间开了一新的的空间,不再是绑定关系,删除之后,才会恢复绑定关系
再看代码
class group: hobby=[‘eat‘,‘drink‘,‘swim‘] wjw=group jjs=group print(group.hobby)#print(group.hobby) print(wjw.hobby)#print(group.hobby) print(jjs.hobby)#print(group.hobby) wjw.hobby.pop() print(group.hobby)#[‘eat‘, ‘drink‘] print(wjw.hobby)#[‘eat‘, ‘drink‘] print(jjs.hobby)#[‘eat‘, ‘drink‘]
类里的名字有 类变量(静态属性量)+ 方法名(动态属性)
对象里的名字 对象属性
对象 —— > 类
对象找名字 : 先找自己的 找类的 再找不到就报错
对象修改静态属性的值
对于不可变数据类型来说,类变量最好用类名操作
对于可变数据类型来说,对象名的修改是共享的,重新赋值是独立的
面向对象的三大特征:继承,多态,封装
继承
单继承
父类又称超类,基类
子类又称派生类
class A: def fun(self): print(‘A‘) pass class B: def fun(self): print(‘B‘) pass class A_son(A): def fun(self): print(‘A_son(A)‘) pass class AB_son(A,B): def fun(self): print(‘AB_son(A,B)‘) pass print(A_son.__bases__)#(<class ‘__main__.A‘>,) 表示A的子类 print(AB_son.__bases__)#(<class ‘__main__.A‘>, <class ‘__main__.B‘>)表示A和B的子类
提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
继承与抽象:向抽象在继承。
请看代码
class People: def eat(self): print(‘%s eat a bread‘%self.name) def sleep(self): print(‘%s is slepping‘%self.name) def look_for_sex(self): print(‘%s is %s‘ % (self.name, self.sex)) class Xiaoming(People): def __init__(self,name,sex): self.name=name self.sex=sex class Xiaohong(People): def __init__(self,name,sex): self.name=name self.sex=sex xiaoming=Xiaoming(‘xiaoming‘,‘male‘) xiaohong=Xiaohong(‘xiaohong‘,‘female‘) xiaoming.eat()#xiaoming eat a bread xiaohong.look_for_sex()#xiaohong is female
注意:此时的父类定义时没有传参数,故可以直接调用
派生
子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类)。
需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
class A: def func(self): print(‘it is father function‘) class B(A): def func(self): print(‘it is son function‘) b= B() b.func()#it is son function
父类中没有的属性 在子类中出现 叫做派生属性
父类中没有的方法 在子类中出现 叫做派生方法
只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错
如果父类 子类都有 用子类的
如果还想用父类的,单独调用父类的:
父类名.方法名 需要自己传self参数
super().方法名 不需要自己传self
在外部调用父类方法是super().方法名 需要自己在(父类名,参数(一般为子类名))
注意区分内外掉用区别
super().hahaha() 等价super(B,self).hahaha(),一般用前面的
正常的代码中 单继承 === 减少了代码的重复
继承表达的是一种 子类是父类的关系
关于继承传参数
class A: def __init__(self,name,sex,age): self.name=name self.age= age self.sex=sex print(‘A传参数完成‘) class B(A): def __init__(self,name,age,sex,hobby): super().__init__(name,age,sex) # super(B, self).__init__(name, age, sex) #也可以这么写,这样就能统一self self.hobby=hobby print(‘hobby传参完成‘) a =B(‘alex‘,16,‘male‘,‘study‘) #结果 #A传参数完成 #hobby传参完成
多继承:
多继承中,我们子类的对象调用一个方法,默认是就近原则,找的顺序是什么?
经典类中 深度优先
新式类中 广度优先
python2.7 新式类和经典类共存,新式类要继承object
python3 只有新式类,默认继承object
经典类和新式类还有一个区别 mro方法只在新式类中存在
类名.mro() 查找多继承的顺序
super 只在python3中存在
super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的
砖石继承
抽象类与接口类
接口类 : python原生不支持
抽象类 : python原生支持
规范 :接口类或者抽象类都可以
接口类 支持多继承,接口类中的所有的方法都必须不能实现 —— java
抽象类 不支持多继承,抽象类中方法可以有一些代码的实现 —— java
接口类
from abc import ABCMeta,abstractmethod class start_game(metaclass=ABCMeta): @abstractmethod def start(self,num):pass class LOL(start_game): def start(self,num): print(‘%s second will be open Lol‘%num) class DNF(start_game): def start(self,num): print(‘%s second will be open DNF‘ % num) class QQ(start_game): def begin(self,num): print(‘%s second will be open QQ‘ % num) lol=LOL() lol.start(5)#5 second will be open Lol dnf=DNF() dnf.start(6)#6 second will be open DNF qq = QQ() qq.begin(5)#TypeError: Can‘t instantiate abstract class QQ with abstract methods start
解析
接口内的多继承
from abc import abstractmethod,ABCMeta class Swim_Animal(metaclass=ABCMeta): @abstractmethod def swim(self):pass class Walk_Animal(metaclass=ABCMeta): @abstractmethod def walk(self):pass class Fly_Animal(metaclass=ABCMeta): @abstractmethod def fly(self):pass class Tiger(Walk_Animal,Swim_Animal): def walk(self): pass def swim(self): pass class OldYing(Fly_Animal,Walk_Animal):pass class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass
抽象类
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案
import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type=‘file‘ @abc.abstractmethod #定义抽象方法,无需实现功能 def read(self): ‘子类必须定义读功能‘ with open(‘filaname‘) as f: pass @abc.abstractmethod #定义抽象方法,无需实现功能 def write(self): ‘子类必须定义写功能‘ pass class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print(‘文本数据的读取方法‘) def write(self): print(‘文本数据的读取方法‘) class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print(‘硬盘数据的读取方法‘) def write(self): print(‘硬盘数据的读取方法‘) class Process(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print(‘进程数据的读取方法‘) def write(self): print(‘进程数据的读取方法‘) wenbenwenjian=Txt() yingpanwenjian=Sata() jinchengwenjian=Process() #这样大家都是被归一化了,也就是一切皆文件的思想 wenbenwenjian.read() yingpanwenjian.write() jinchengwenjian.read() print(wenbenwenjian.all_type) print(yingpanwenjian.all_type) print(jinchengwenjian.all_type)
#输出结果
#文本数据的读取方法
#硬盘数据的读取方法
#进程数据的读取方法
#file
#file
#file
以上是关于面向对象的主要内容,如果未能解决你的问题,请参考以下文章