多态

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 对象.属性  删除属性时 执行

为对象设置属性的两种方法(非常重要****)

增加属性就是增加到名称空间中

  1. 这个说明通过super()._setattr_()的方法增加属性!!!

  2. 另一个增加属性的方法:直接操作_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)
原文地址:https://www.cnblogs.com/ZDQ1/p/11266125.html