1.什么是多态?
多态指的是一类事物有多种形态
例如:动物有多种形态:
人,狗,猪
在程序中多态指的是,不同对象可以响应相同方法,并可以有自己不同的实现方式
1.1多态的应用
'''
要管理 鸡 鸭 鹅
如何能够最方便的 管理,就是我说同一句话,他们都能理解
既它们拥有相同的方法
'''
class Checken:
def bark(self):
print('gegege')
def lay(self):
print('下蛋了')
class E:
def bark(self):
print('鹅鹅鹅')
def lay(self):
print('下鹅蛋')
def manage(obj):
obj.bark()
obj.lay()
j=Checken()
e=E()
# j.bark()
# j.lay()
# e.bark()
# e.lay()
manage(j)
manage(e)
那么多态的带来的好处是什么?
1.增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)*
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用*
'''
这样我们新增了一个形态Cat,由Cat类产生的实例cat1,使用者可以在完全不需要修改自己代码的情况下。使用和人、狗、猪一样的方式调用cat1的talk方法,即manage(obj)
'''
class Cat(): #动物的另外一种形态:猫
def bark(self):
print('say miao')
def manage(obj):#对于使用者来说,自己的代码根本无需改动
obj.bark()
obj.lay()
cat1=Cat() #实例出一只猫
mange(cat1) #甚至连调用方式也无需改变,就能调用猫的talk功能
say miao
python到处都有多态
a=10
b='10'
c=[10]
print(type(a),type(b),type(c))
<class 'int'> <class 'str'> <class 'list'>
2.魔法函数
isinstance
对象是否为类的实例
add_num(a,b):
return a+b
add_num('1',1)
#报错
#解决1:加入条件判断
add_num(a,b):
if type(a)==int and type(b)==int:
return a+b
else:
print('类型错误')
add_num('1',1)#类型错误
'''
解决2:instances
'''
def add_num(a,b):
if isinstance(a,int) and isinstance(b,int):
return a+b
else:
print('类型错误')
add_num('1',1)#类型错误
issubclass
判断一个类是不是另一个类的子类
class Animal:
def eat(self):
print("动物得吃东西...")
class Pig(Animal):
def eat(self):
print("猪得吃 猪食....")
class Tree:
def light(self):
print("植物光合作用....")
def manage(obj):
# if type(obj) == Pig:
# obj.eat()
if issubclass(type(obj),Animal):
#判断一个类是不是另一个类的子类
obj.eat()
else:
print("不是一头动物!")
pig = Pig()
t = Tree()
# manage(pig)
manage(t)
manage(pig)
str
__str__ 会在对象被转换为字符串时,转换的结果就是这个函数的返回值
使用场景:我们可以利用该函数来自定义,对象的是打印格式
class Person(object):
def __str__(self):
return 'abc'
p=Person()
print(p)
结果为‘abc’
del
执行时机: 手动删除对象时立马执行,或是程序运行结束时也会自动执行
class Person:
def __init__(self,name,age):
self.name =name
self.age=age
def __del__(self):
print('del run')
p=Person('wx',18)
结果 del run
使用场景:当你的对象在使用过程中,打开了不属于解释器的资源:例如文件,网络端口
#1、手动指定关闭
class Filltool:
def __init__(self,path):
self.file= open(path,encoding='utf-8')
def read(self):
# return self.read()
return self.file.read()
tool=Filltool('a.txt')
print(tool.read())
tool.file.close()#在此时关闭
#1、在程序执行完关闭
class Filltool:
def __init__(self, path):
self.file = open(path, encoding='utf-8')
def read(self):
# return self.read()
return self.file.read()
def __del__(self):
self.file.close()
tool = Filltool('a.txt')
print(tool.read())
call
执行时机:在调用对象时自动执行,(既对象加括号)
测试:(没什么使用场景)
class A:
def __call__(self, *args, **kwargs):
print('call run')
print(args)
print(kwargs)
a=A()
a(1,a=10)
slots
该属性是一个类属性,用于优化对象内存占用
优化的原理,将原本不固定的属性数量,变得固定了
这样的解释器就不会为这个对象创建名称空间,所以__dict__也没了
从而达到减少内存开销的效果
另外当类中出现了slots时将导致这个类的对象无法在添加新的属性
# slots的使用
import sys
class Person:
def __init__(self, name):
self.name = name
p = Person('wx')
#浪费系统资源,随机开50%的空间,导致空间浪费
#牺牲空间提高效率
print(sys.getsizeof(p))
# 56
class Person:
#节约内存,固定死属性
__slots__ = ['name']
def __init__(self, name):
self.name = name
p = Person('wx')
print(sys.getsizeof(p))
# 48
此时不会创建名称空间
print(p.__dict__)
#报错
点语法的实现
1、getattr 2、setattr3、 delattr
getattr 用点访问属性的时如果属性不存在时执行
setattr 用点设置属性时
delattr 用del 对象.属性 删除属性时 执行
为对象设置属性的两种方法(非常重要****)
增加属性就是增加到名称空间中
-
这个说明通过super()._setattr_()的方法增加属性!!!
-
另一个增加属性的方法:直接操作_dict_
第一个方案其实就是利用的第二个方案!
b=A()
print(b.__dict__)#{}
b.__dict__["name"]='wx'#看上面一个打印结果,证明现在的b对象名称空间
# 没有任何内容,对象的名称是一个字典,通过字典赋值的方法,增加属性!!!
print(b.name)#wx
print(b.__dict__)#{'name': 'wx'}
现在我们会了第二种方法,就可以这么写了:如下
setattr(self,key,value)key和value分别代表什么?
setter代表Python内部的实现原理:
del a.name
class A:
def __getattr__(self, item):
print(11111)
print("__getattr__")
def __setattr__(self, key, value):
print("__setattr__")
self.__dict__[key]=value
def __delattr__(self, item):#name。item是上面的K,也就是属性,不是属性的值!!
print("__delatr__")
print(item)
self.__dict__.pop(item)
关于getattr(****)
关于getattribute
不****管有没有该属性,多会走该函数!!!
getattribute 该函数也是用来获取属性
getattribute在获取属性时 如果属性 存在,getattribute则先执行该函数,如果没有拿到属性则无限循环继续调用 getattr函数
class A:
def __getattr__(self, item):
print('__getattr__')
def __setattr__(self, key, value):
print('__setattr__')
def __delattr__(self, item):
print('__delattr__')
a=A()
a.name= 'wx'
print(a.name)
结果
__setattr__
__getattr__
None
解决:在setattr下面加入
class A:
def __getattr__(self, item):
print('__getattr__')
def __setattr__(self, key, value):
super().__setattr__(key, value)
print('__setattr__')
def __delattr__(self, item):
print('__delattr__')
a=A()
a.name= 'wx'
print(a.name)
结果:
__setattr__
wx
操作属性的第二种方式
实际上方式一(点语法)内部也是该方式。
self.__dict__[key]=value
#__dict__的打印结果是字典
b=A()
b.__dict__['name']='sll'
print(b.name)
print(b.__dict__)
sll
{'name': 'sll'}
delattr 用del 对象.属性 删除属性时 执行
def __delattr__(self, item):
print('__delattr__')
del a.name
print(a.name)
有值,并没有删除
加入命令self.__dict__.pop(item)
def __delattr__(self, item):
print('__delattr__')
self.__dict__.pop(item)
del a.name
print(a.name)
1、getattr 2、setattr3、 delattr这三个函数,反应了python解释器是如何实现‘’点‘’的访问属性
getattribute
class A:
def __getattr__(self, item):
print('__getattr__')
return 1
def __getattribute__(self, item):
print('__getattribute__')
return super().__getattribute__(item)
a=A()
a.name= 'wx'
print(a.name)
#结果
__getattribute__
wx
与getattr类似。
获取属性:若存在,则执行,若没找到属性,则先走完getattribute再走getattr,拿到值就返回
a=A()
a.name= 'wx'
print(a.age)
#执行结果
__getattribute__
__getattr__
1
[] 的实原理
getitem setitem delitem
python如何用[]取值?
任何的符号 都会被解释器解释成特殊含义 ,例如 . [] ()
getitem 当你用[中括号]去获取属性时 执行
setitem 当你用[中括号]去设置属性时 执行
delitem 当你用[中括号]去删除属性时 执行
class A:
def __getitem__(self, item):
print("__getitem__")
return self.__dict__[item]
def __setitem__(self, key, value):
print("__setitem__")
self.__dict__[key] = value
def __delitem__(self, key):
del self.__dict__[key]
print("__delitem__")
a = A()
# a.name = "jack"
a["name"] = "jack"
print(a["name"])
del a["name"]
print(a["name"])
需求:让一个对象支持点语法取值和[]取值?
class MyDict(dict):
def __getattr__(self, key):
return self.get(key)
def __setattr__(self, key, value):
self[key] = value
def __delattr__(self, item):
del self[item]
a=MyDict()
a['name']='wx'
print(a['name'])
print(a.name)
wx
运算符重载
当我们在使用某个符号时,python解释器都会为这个符号定义一个含义,同时调用对应的处理函数, 当我们需要自定义对象的比较规则时,就可在子类中覆盖 大于 等于 等一系列方法....
gt为大于
class Student(object):
def __init__(self,name,height,age):
self.name=name,
self.height= height
self.age = age
def __gt__(self, other):
return self.height >other.height
a=Student('wx',75,30)
a1=Student('sll',47,23)
print(a>a1)
True
不加__gt__的话默认是比较内存地址
gt为 greater than大于的缩写
lt为less than小于的缩写
qt为equal to等于的缩写
迭代器协议
迭代器是指具有__iter__和__next__的对象
我们可以为对象增加这两个方法来让对象变成一个迭代器
案例:
class MyRange:
def __init__(self, start, end, step):
self.start = start
self.end = end
self.step = step
def __iter__(self):
return self
def __next__(self):
a = self.start
self.start += self.step
if a < self.end:
return a
else:
raise StopIteration
for i in MyRange(1,10,2):
print(i)
结果为:
1
3
5
7
9
class MyIter:
'''
num传入 用来指定迭代的次数
'''
def __init__(self, c,num):
self.num = num
self.c = c
def __iter__(self):
return self
def __next__(self):
self.c+=1
if self.c<self.num:
return '哈哈'
else:
raise StopIteration
for i in MyIter(1,10):
print(i)
哈哈
哈哈
哈哈
哈哈
哈哈
哈哈
哈哈
哈哈
上下文管理
上下文 context
这个概念属于语言学科,指的是一段话的意义,要参考当前的场景,既上下文
在python中,上下文可以理解为是一个代码区间,一个范围 ,例如with open 打开的文件仅在这个上下文中有效
涉及到的两个方法:
enter
表示进入上下文,(进入某个场景 了)
exit
表示退出上下文,(退出某个场景 了)
当执行with 语句时,会先执行enter ,
当代码执行完毕后执行exit,或者代码遇到了异常会立即执行exit,并传入错误信息
包含错误的类型.错误的信息.错误的追踪信息
class MyOpen(object):
def __init__(self,path):
self.path = path
def __enter__(self):
self.file = open(self.path)
print('enter...')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('exit...')
self.file.close()
return True
with MyOpen('a.txt') as m :
print(m)
m.file.read()
```![](https://img2018.cnblogs.com/blog/1689626/201908/1689626-20190824202117039-1448877764.png)
![](https://img2018.cnblogs.com/blog/1689626/201908/1689626-20190824202152831-12895749.png)