python面向对象的三大特性继承 多态 封装
1 继承
python的继承分为单继承和多继承,新建的类被成为派生类或者子类,而继承的类被成为父类或者超类
查看继承关系
使用__bases__方法查看所有继承对象------》 对象.__bases__
如果没有指定继承父类,则python3中则默认所有的类都继承object类,也叫新式类。
继承与抽象的关系
一定是将对象中的类似的内容抽象出来,在进行继承
软件的重用
如果我们在开发过程中,需要写一个新类,而这个类的功能和已存在的类功能相似,那么就可以通过继承,获得部分的功能,减少代码量
同样的标准库或者第三方库同样可以被继承
派生
新类中也可以有自己的属性和方法,其中属性成为派生属性,方法成为派生方法。但是在定义的时候,要注意尽量别和父类的属性名和方法名重复,因为在调用的时候,如果新类中有,就回优先使用自己的而不去找父类的。
如果新类中的方法需要用到父类中同名的方法,则可以使用类名.方法名()方法名直接调用,也可以使用supper()方法直接调用
# class animal:
# def __init__(self,name,aggr,hp):
# self.name=name
# self.aggr=aggr
# self.hp=hp
#
# def eat(self):
# self.hp+=100
# class dog(animal):
# def __init__(self,name,aggr,hp,kind):
# animal.__init__(self,name,aggr,hp)# 这里的self 是dog的self
# self.kind=kind #派生属性 在父类的基础之上又派生了新的属性
# def bite(self,person): #派生方法 在父类的基础上有派生了新的方法
# person.hp-=self.aggr
#
# def eat(self):
# """
# 如果迹象实现新的功能也想使用父类原本的功能,还需要在子类中在掉用父类
# :return:
# """
# animal.eat(self)# 这里的self是dog 作为参数传给了animal.eat
# self.teeth = 2
# class person(animal):
# def __init__(self,name,aggr,hp,sex):
# animal.__init__(self,name,aggr,hp)
# self.money=0
# self.sex=sex
#
# def attack(self,dog):
# dog.hp-=self.aggr
#
# def get_weson(self,weson):
# pass
#
# jin=dog('二哈',100,500,'哈士奇')
# jin.eat()
# print(jin.hp)
# dan=person('dandan',20,100,'baobao')
# dan.eat()
# print(dan.hp)
# jin.bite(dan)
# print(dan.hp)
super()用法
class animal:
def __init__(self,name,aggr,hp):
self.name=name
self.aggr=aggr
self.hp=hp
def eat(self):
self.hp+=100
print('吃药回血')
class dog(animal):
def __init__(self,name,aggr,hp,kind):
#super(dog,self).__init__(name,aggr,hp) supper内参数可以不传
super().__init__(name, aggr, hp)
self.kind=kind
def eat(self):
print('dog eating')
jin=dog('二哈',200,100,'哈士奇')
print(jin.name)
jin.eat()
super(dog,jin).eat() #如果是在类外 使用supper(类名,实例化名).方法() 就会执行类中的方法
python中的抽象类和接口类:
python原生不支持接口类,接口类是java的概念,在python中可以将接口类看成抽象类。抽象类无法被实例化
,且内部方法不能被实现。抽象类和接口类更像是一种类的规范。
python中的继承包括两种用途:
1 继承父类的方法,并且有自己改变或者扩展(派生)
2 声明某个子类兼容与某父类,就是定义一个接口类interface,接口类中定义了一些接口名但 是未能实现,子类继承接口类,必须要实现继承的接口类中的方法。
在实际工作中,继承的第一种用法含义并不大,因为它是的子类与父类穿线强耦合
第二种比较重要,叫着接口的继承。接口继承实际上要求做出一个良好的抽象,这个抽象规定了一个兼容接口,是的外部调用者无序关心具体袭击,可以一视同仁的处理实现了特定接口的所有对象--这种程序上的设计叫做归一化。类似与linux的泛文件概念。
# from abc import abstractclassmethod,ABCMeta
# class Payment(metaclass=ABCMeta):# 元类 默认的元类 type 这里指定元类为ABCmeta 规范一个类
# @abstractclassmethod
# def pay(self,money):
# pass
# # class Payment1:
# # def pay1(self):
# # raise NotImplemented #没有实现这个方法,也就是子类中没有实现父类的方法就会主动抛出异常
# class Wechat(Payment):
# def pay(self,money):
# print('已经使用微信支出%s',money)
# class alichat(Payment):
# def pay(self,money):
# print('已经使用ali支出%s',money)
# class appchat(Payment):
# def pay1(self,money):
# print('已经使用app支出%s',money)
# def pay(pay_obj,money): #统一支付接口
# pay_obj.pay(money)
# we=Wechat()
# app=appchat()
# pay(we,199)
# pay(app,300)
接口类的继承:
# from abc import abstractclassmethod,ABCMeta
# class swim_animal(metaclass=ABCMeta):
# @abstractclassmethod
# def swim(self):
# pass
#
# class walk_animal(metaclass=ABCMeta):
# @abstractclassmethod
# def walk(self):
# pass
#
# class fly_animal(metaclass=ABCMeta):
# @abstractclassmethod
# def fly(self):
# pass
#
# class tiger(swim_animal,walk_animal,fly_animal):
# def swim(self):
# print('tiger swim')
# def walk(self):
# print('tiger swim')
# def fly(self):
# print('tiger swim')
python中利用abc模块实现抽象类:在py3.4之后,@abc.abstractclassmethod被弃用,所以pycharm会在该装饰器函数上画一条横线
import abc #利用abc模块实现抽象类
class all_file(metaclass=abc.ABCMeta):
all_type='file'
@abc.abstractclassmethod
def read(self):#定义抽象方法,无需实现功能,当然也可以实现部分功能
'子类必须定义读功能'
print('all_file read')
pass
@abc.abstractclassmethod
def write(self):
'子类必须定义写功能'
pass
class txt(all_file):
def read(self):
print('txt read')
def write(self):
print('txt write')
t1=txt()
t1.read()
t1.write()
print(t1.all_type)
继承的顺序:
1 python中的类可以继承多个类,java和c#只能继承一个类
2 python中的类如果继承了多个类,那么其寻找方法的方式有两种,分别是广度优先和深度优先。如果是经典类,多继承下是深度优先,如果是新式类多继承下是广度优先,在python中都是新式类。
原理:
如果你定义一个类,python会计算出一个方法解析顺序mro列表,这个mro列表即使一个简单的所有父类的线性顺序列表
父类的mro列表回遵循如下三条准则
1 子类会先于父类被检查,如果子类和父类中有相同的方法名的时候 要特别注意。
2 多个父类会根据它们在列表中的顺序被检查
3 如果对下一个类存在两个合法的选择,选择第一个父类
多态
python中天生支持多态。一种事物有多种形态,强类型语言需要定义参数类型,python是动态强类型语言,比如2+str=2str 但python中会报类型错误
百度中的概念:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。
import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
@abc.abstractmethod
def talk(self):
pass
class People(Animal): #动物的形态之一:人
def talk(self):
print('say hello')
class Dog(Animal): #动物的形态之二:狗
def talk(self):
print('say wangwang')
class Pig(Animal): #动物的形态之三:猪
def talk(self):
print('say aoao')
peo=People()
dog=Dog()
pig=Pig()
#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()
#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
obj.talk()
封装:
代码的保护,面向对象的思想本身就是一种封装,只让自己的对象调用自己类中的方法。就是将属性和方法都藏起来。
类的私有:
所有的私有,都是在变量的左边加上双下划线
1 对象的私有属性
2 类中的私有方法
3 类中的静态私有属性
所有的私有,都不能在类的外部使用
#类的私有属性 只是在代码层面不允许用 对象.属性的方式调用
# class userinfo:
# __key=123 #私有的静态属性
# def __init__(self,name,pwd):
# self.name=name
# self.__pwd=pwd #私有属性
# def get_pwd(self):
# # 只要在类的内部使用私有属性,就会自动带上 _类名
# # 注意如果此时在类的外部调用pwd 需要用 _userinfo__pwd
# # 这一点可以通过在外部定义一个 带下划线的方法来实验例如 yuan._pwd1
# # 这样在外部依然可以用 yuan._pwd1来调用该方法
# print('get_pwd--》',self.__dict__)
# return self.__pwd
#
# def __user_name(self):
# #私有的方法 只在内部使用 外部没办法感知
# print(self.__dict__)
# print('__user_name')
# def use(self):
# print('use',self.__dict__)
# self.__user_name()
# yuan=userinfo('dandan',123456)
# print(yuan.name)
#
# #print(yuan.__pwd) 会报错
# print(yuan.__dict__) 查看self之后看到对象中没有__pwd,所以需要yuan._userinfo__pwd的方式调用
# print(yuan._userinfo__pwd) #_类名__属性
# yuan._weight=100 #设定对象的隐藏方法
# print(yuan._weight)
# print(yuan.use())
#假设父类的私有属性,能被子类调用??
class foo:
__y='212'
class son(foo):
#print(foo.__key)
pass
#弱项调用必须在外部调用需要以下列方式
# print(son._foo__y)
property classmethod staicmethod用法:
'''
遗留的内置函数
property
classmethod
staticmethod
'''
#property 内置装饰器函数,只在面向对象中使用
#被property装饰的方法不能传任何参数
# 只是使类中的方法看起来更像是一个属性,
# 在类的外部调用该方法的时候,不用加()调用
from math import pi
# class circle:
# def __init__(self,r):
# self.r=r
# @property
# def perimeter(self):
# return 2*pi*self.r
# @property
# def area(self):
# return pow(self.r,2)*pi
#
# c1=circle(6)
# print(c1.perimeter)
# print(c1.area)
# class person:
# def __init__(self,name,high,weight):
# self.name=name
# self.high=high
# self.weight=weight
# @property
# def bmi(self):
# return self.weight/self.high**2
# @property
# def fab_bmi(self):
# return 22*pow(self.high,2)
#
# yuan=person('袁',1.74,91)
# print(yuan.bmi)
# print(yuan.fab_bmi)
#利用property 修改类的私有属性
#property 可以看成将方法置成了一个类的属性 在外部是不能被更改的
#需要配合 @被property装饰的函数同名.setter 在定义一个新的和被property装饰的方法同名的方法才能完成修改
#所以如果想使用 @被property装饰的函数同名.setter 更改则必须先使用@property
# class edit_name:
# def __init__(self,name):
# self.__name=name
# @property
# def name1(self):
# return self.__name+'sb'
#
# @name1.setter
# def name1(self,new_name):
# print('name1 edit')
# self.__name=new_name
#
# cat=edit_name('dandan')
# print(cat.name1)
# cat.name1='wangyongmei'
# print(cat.name1)
# class goods:
# discount=0.8
# def __init__(self,name,price):
# self.name=name
# self.__price=price
# @property
# def price(self):
# return self.__price*goods.discount
# app=goods('玉米',6)
# print(app.price)
#属性的删除 修改 查看
# class del_name:
# def __init__(self,name):
# self.__name=name
# @property
# def name1(self):
# return self.__name
# @name1.deleter
# def name1(self):
# print('执行了这个方法')
# del self.__name
# @name1.setter
# def name1(self,newname):
# self.__name=newname
#
# del_oldname=del_name('niu')
# print(del_oldname.name1)
# print(del_oldname.__dict__)
#
# #del 只是触发了类中 @被property装饰的函数同名.deleter 装饰的方法
# del del_oldname.name1
# print(del_oldname.__dict__)
# #print(del_oldname.name1)
'''
method 方法
staticmethod 静态的方法
classmethod 类方法
把一个方法变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
当这个方法的操作只设计静态属性的时候,就应该使用classmethod来装饰这个方法
'''
# class goods:
# __discount=0.8
# def __init__(self,name,price):
# self.name=name
# self.__price=price
# @property
# def price(self):
# return self.__price*goods.__discount
# @classmethod #把一个方法变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
# def change_discont(cls,newdiscont):
# cls.__discount=newdiscont
#
# app=goods('玉米',6)
# print(app.price)
# goods.change_discont(0.6)
# print(app.price)
#面向对象编程 staticmethod 方法
class Login:
def __init__(self,name,password):
self.name=name
self.password=password
def login(self):
pass
@staticmethod
def get_user():
user=input('usename')
pwd=input('pwd')
Login(user,pwd)
Login.get_user()
#在完全面向对象的程序中
#如果一个函数,既和对象没有关系,也和类没有关系,那么就用staticmethod将这个函数变成一个静态方法
#类方法,有一个默认参数cls,代表这个类cls
#静态方法 没有默认的参数,就像函数一样
反射 hasattr getattr deattr:
'''
反射
hasattr getattr deattr
'''
class teacher:
dic={'查看学生信息':'show_student','查看讲师信息':'show_teacher'}
@classmethod
def show_student(cls):
print('show_student')
@classmethod
def show_teacher(self):
print('show_teacher')
@classmethod
def func(cls):
print('sdf')
# ret=getattr(teacher,'dic') #teacher.dic 类也是对象,需要注意的是被调用的函数是实例函数还是类函数,如果是实例函数则需要实例化类-->
# print(ret)
# ret01=getattr(teacher,'func') #teacher.func()
# ret01()
# if hasattr(teacher,'show_student'):
# ret02=getattr(teacher,'show_student')
# print(ret02)
# ret02()
#
#
# yuan=teacher()
# ret03=getattr(yuan,'show_teacher')
# ret03()
for k in teacher.dic:
print(k)
key_info=input("pelase select info")
if hasattr(teacher,key_info):
ret7=getattr(teacher,teacher.dic[key_info])
ret7()
'''
通过反射
对象名 获取对象属性和普通方法
类名 获取静态属性和类方法和静态方法
1 同样,若不想正常调用模块中的方法,可以采用反射
2 内置模块也能用
import time
# time.asctime()
ret9=getattr(time,'asctime')
print(ret9())
'''
3 反射自己模块中的变量
# import sys
# def cap():
# print('反射自己模块中变量')
# return '反射自己模块中变量01'
# year=2018
# ret4=getattr(sys.modules['__main__'],'year')
# print(ret4)
# #反射自己模块中的函数
# ret5=getattr(sys.modules['__main__'],'cap')
# print(ret5())
类的内置方法:
'''
类的内置方法
类的内置方法 和 内置函数之间有着千丝万缕的联系
双下方法
__str__
object 里边有个__str__,一旦被调用,就返回调用这个方法的对象的内存地址
__str__返回的一定是个字符串
__repr__
%s str() 直接打印 实际上执行的是 __str__
%r repr() 实际上是__repr__
repr是str的备胎,但是str不能做repr的备胎
str(obj) 实际上是内部调用了obj.__str__方法,如果str方法有,那么它必须返回一个字符串
如果没有__str__方法,回系按照本类 __repr__方法,再没有再找父类中的__str__
repr() 只会找__repr__ 如果没有找父类的
'''
# class a:
# def __str__(self):
# return 'a'
#
# a1=a()
# print(a1) #打印一个对象的时候,就是调用a.__str__
# #a1.__str__ ---》object
# #object 里里边有个__str__ 一旦被调用,就返回调用这个方法的对象的内存地址
#
# l=[1,2,3,4] #实例化了一个列表对象
# print(l) #---->实际上 调用了 __str__
# class teacher:
# def __init__(self,name,salary):
# self.name=name
# self.salary=salary
# def __str__(self):
# return 'teacher object :%s'%self.name
#
# def __repr__(self):
# return str(self.__dict__)
# def func(self):
# return 'dddddd'
#
# wukong=teacher('aoteman',252)
# print(str(wukong))
# print(repr(wukong))
# print('%r'%wukong) #自己有__repr__ 就用自己的 如果没有 就调用父类的object
# class cla:
# def __init__(self,name):
# self.name=name
# self.studen=[]
# def __len__(self):
# print('len1')
# # 这个地方self.studen不是实例化对象所以不会调用自己的双下len方法,
# # 但是如果写成len(self)就回默认调用自己的双下len方法,因为self指的是类的本身
#
# # __len__方法是cla类的内置方法,根据继承可知,实例在调用方法的时候,会先调自己的
# #所以在外部调用len(实例化对象) 会调自己的__len__方法
# #但是在return的时候又了一次len方法,但是传入的是一个实例化的列表对象
# #所以这个return的len实际上是调用list的__len__方法,list自己没有__len__方法,所以最终调用的还是object的
# return len(self.studen)
# ps=cla('py9')
# ps.studen.append('dsf')
# ps.studen.append('dsf')
# print(len(ps))
#
# '''
# __del__ 析构函数
# 在删除一个对象之前,进行一些收尾工作
'''
# class af:
# def __del__(self): #析构函数 在删除一个对象前进行一些收尾工作
# self.f.close()
# a123=af()
# a123.f=open() #打开文件1 在操作系统中打开一个文件 拿到文件操作符存在内存中
# del a123 #直接删除a123 等于也删除了a123.f拿到的了文件操作符,但是此时系统中的文件并没有关闭
#引用计数 python的垃圾回收机制 如果检测到下边还有地方引用a123或者类 计数+1如果没有就制程0
#
# '''
# __call__ 一个对象加() 等于执行类内部的__call__方法
#
# '''
class yu:
def __init__(self,name):
self.name=name
def __call__(self):
print('内置call方法被执行')
a=yu('ni')()
item __getiem__ __setitem__ __delitem__ 支持字典增删改查,查看字典源码,其实也是这样写的,包含列表,只是多了一种取值方法。
# class foo(object):
# def __init__(self,name,age,sex):
# self.name=name
# self.age=age
# self.sex=sex
# def __getitem__(self, item):
# if hasattr(self,item):
# return self.__dict__[item]
# def __setitem__(self, key, value):
# self.__dict__[key]=value
# def __delitem__(self, key):
# del self.__dict__[key]
#
# f=foo('yuan',18,'man')
# print(f['name'])
# f['like']='son'
# print(f.like) #object原生支持
# print(f.like,f['like']) #通过自己实现的
# print(f.__dict__)
# del f['like']
# print(f.__dict__)
__init__ 初始化方法 __new__ 创建一个对象。其实类的实例化时,是默认执行了object的__new__方法,用于构建一个self
# class a:
# def __init__(self):
# self.x=1
# print('init function')
# def __new__(cls, *args, **kwargs):
# print('__new__')
# return object.__new__(a,*args,**kwargs) #这里class a并没有能实现构造的方法 所以还是需要调用object的
# b=a()
单例模式 __new__ 一个类始终只有一个实例,限制一个类从头到位只有一个实例,当你之后再来实例化的时候看就用之前创建的对象
#23种
#__new__ 单例模式
# 一个类始终只有一个实例 限制一个类从头到尾只有一个实例
# 当你之后再来实例化的时候看就用之前创建的对象
# class b:
# __insta=False
# def __init__(self,name,age):
# self.name=name
# self.age=age
# def __new__(cls, *args, **kwargs):
# '''
# 在外部实例化该类的时候,回执行类中的双下new方法
# 通过判断_insta的真假,返回不同的返回值,在第一次
# 实例化该类的时候,其实通过在类的内部改变了私有__insta的方法
# 当下次再实例化调用时,就返回已经变更过的私有__insta方法
#
# '''
# if cls.__insta:
# return cls.__insta
# cls.__insta=object.__new__(b)
# return cls.__insta
# egon=b('agg',38)
# nezha=b('nazha',25)
# print(nezha)
# print(egon)
# print(nezha.name)
# print(egon.name)
__eq__ 和 __hash__
# class f:
# def __init__(self,name):
# self.name=name
#
# def __eq__(self, other):
# if self.name==other.name:
# return True
# else:
# return False
# yu1=f('yuan')
# yu2=f('yuan')
# print(yu1==yu2)
class h:
def __init__(self,name,sex):
self.name=name
self.sex=sex
def __hash__(self):
return hash(self.name+self.sex)
h1=h('yu','man')
h2=h('yu','man')
print(hash(h1))
print(hash(h2))
set 依赖__hash__ __eq__
class hashs:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def __eq__(self, other):
print(self,other)
print('eq2222')
if self.name==other.name and self.sex==other.sex:
return True
else:
return False
def __hash__(self):
print('hash111')
return hash(self.name+self.sex)
a=hashs('yuan',18,'man')
b=hashs('yuan',25,'man')
#set的实现 依赖对象hash eq方法 先调用hash 拿到hash值 在调用eq
print(set((a,b)))
hs=set((a,b))
print(hs)
其他的内置方法
类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中)
类的组合
'''
面向对象的三大特性: 继承 多态 封装
类的组合:一个对象的属性值是另外一个类的对象
w=weapon('粪叉子',100,3,200)
yuanbao.get_weapon(w) 通过self 将武器对象绑定成自己的属性值
yuanbao.weapon.hand18(jin)
'''
# class dog:
# def __init__(self,name,aggr,hp,kind):
# self.name=name
# self.aggr=aggr
# self.hp=hp
# self.kind=kind
# def bite(self,person):
# person.hp-=self.aggr
# print('%s被狗咬了,掉了%s滴血'%(person.name,self.aggr))
#
# class person:
# def __init__(self,name,aggr,hp,sex):
# self.name=name
# self.aggr=aggr
# self.hp=hp
# self.sex=sex
# self.money=0
# def attack(self,dog):
# dog.hp-=self.aggr
# print('%s被人打了,掉了%s滴血'%(dog.name,self.aggr))
# def get_weapon(self,weapon):
# if self.money>weapon.price:
# self.money-=weapon.price
# self.aggr+=weapon.statck
# self.weapon=weapon
# else:
# print('钱不够')
#
# class weapon:
# def __init__(self,name,statck,lasting,price):
# self.name=name
# self.statck=statck
# self.lasting=lasting
# self.price=price
# def hand18(self,person):
# if self.lasting>0:
# person.hp-=self.statck*2
# self.lasting-=1
#
#
#
# yuanbao=person('蛋蛋',2,100,'未知')
#
# jin=dog('二哈',100,500,'teddy')
# w=weapon('粪叉子',100,3,200)
# #充钱
# yuanbao.money=1000
# print(yuanbao.__dict__)
# #装备打狗棒
# yuanbao.get_weapon(w)
# #打狗
# yuanbao.attack(jin)
# print(jin.hp)
#
# #使用打狗棒大招
# yuanbao.weapon.hand18(jin)
# print(jin.hp)
'''
类的组合 :
一个对象的属性是另一类的对象
实际上在A类中将B类的实例化赋值给变量S,然后通过调用的方式使用B中的属性 AA=A.S.func
圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长。
这个时候,我们就首先实现一个圆形类,计算一个圆的周长和面积。然后在"环形类"中组合圆形的实例作为自己的属性来用
'''
# from math import pi
#
# class roundness:
# def __init__(self,r):
# self.r=r
# def permiter(self):
# return pi*self.r*2
# def areas(self):
# return pi*pow(self.r,2)
#
#
# class annulus:
# def __init__(self,outside_r,inside_r):
# self.outs=roundness(outside_r)
# self.inside=roundness(inside_r)
#
#
# def annu_per(self):
# return self.outs.permiter()+self.inside.permiter()
# def annu_areas(self):
# return abs(self.outs.areas()-self.inside.permiter())
#
# ring=annulus(30,20)
# print(ring.annu_areas())
# print(ring.annu_per())
class bir:
def __init__(self,year,month,day):
self.year=year
self.month=month
self.day=day
class teacher:
def __init__(self,name,age,sex,b):
self.name=name
self.age=age
self.sex=sex
self.b=b
birs=bir(2018,12,8)
t1=teacher('yu',18,'man',birs)
print(t1.name)
print(t1.b.year)

浙公网安备 33010602011771号