面向对象之多态以及魔法函数

一:多态

【1】基础概念

(1)基础概念:

  (1)一种事物拥有多种形态:

    例如:水--->气态--->液态--->固态

  (2)在python中是多个对象可以相应同一种方法 产生不同的结果

PS:多态不是一种语法 而是一种特殊的状态 特性 即多个对象有相同的使用方法

例如:

# 案例一
class Chicken:
    def span(self):
        print('下鸡蛋')

class Duck:
    def span(self):
        print('下鸭蛋')

class Goose:
    def span(self):
        print('下鹅蛋')

j = Chicken()

y = Duck()

e = Goose()

j.span() # 下鸡蛋
y.span() # 下鸭蛋
e.span() # 下鹅蛋

# 案例二
a = '10'

b = [10]

c = (10,)

print(len(a),len(b),len(c)) # 2 1 1
多态案例

 

(2)优点:

  (1)增加的程序的灵活性 以不变应万变 无论对象怎么变化 使用者调用方式不变

  (2)如果通过继承类 而创建一个新的类 使用者无需更改自己的代码 还是以原始方式调用

PS:继承 抽象类 鸭子类型都可以写出具备多态的代码 但是鸭子类型更加方便以及快捷

 

【2】内置方法

(1)isinstance:

作用:判断一个对象是否为一个类的实例

例如:

def add_num(x,y):
    # 判断整形是否为某个类
    if isinstance(x,int) and isinstance(y,int):
        return x + y
    return '错误的相加'

# 情景一
 print(add_num('10',20)) # 报错 字符串与整形不能相加

# 情景二 print(add_num('10',20)) # 错误的相加

# 情景三 判断所属的类
print(add_num(10,20)) # 30

PS:

(1)参数一:所传的对象

(2)参数二:所属的类

 

(2)issubclass:

作用:判断一个类是否为一个类的子类

例如:

class Animal:
    def eat(self):
        print('动物需要吃东西!')

class Pig(Animal):
    def eat(self):
        print('猪正在吃猪食!')

class Tree:
    def sunshine(self):
        print('树在进行光合作用!')

def manage(animal):
    # 判断一个类是否为另外一个类的子类
    if issubclass(type(animal),Animal):
        animal.eat()
    else:
        print('不是动物 而是植物!')



pig = Pig()
tree = Tree()

manage(pig)
# 没加条件判断之前
manage(tree)  # 报错 因为tree没有继承Animal

# 添加添加判断
manage(tree) # 不是动物 而是植物!
判断一个类是否为另外一个类子类

 

(3)str

(1)作用:在对象被转换成字符串的时候被调用 调用的结果就是函数的返回值

例如:

class Person:
    def __str__(self):
        print('run')

        return 'SR'

p = Person()

# 没加返回值之前
print(p)  # 报错 希望得到一串字符串返回值

# 添加返回值
print(p)  # 执行函数代码 并且有返回值

str(p) # run
#PS:对象在被转换成字符串的时候 调用__str__函数

PS:

(1)如果对象在被转换成字符串的时候 首先会执行__str__的执行

(2)__str__执行完毕之后 在进行函数的打印

 

(4)del:

作用:手动删除对象的时候 或者程序结束会立马执行释放内存

使用场景:但是其作用不是用来清除解释器中的资源 而是不属于解释器的资源 例如某些文本 端口号等

例如:

class  File:
    # 创建文件的初始属性 赋值函数的地址
    def __init__(self,path):
        self.file = open(path,'rt',encoding='utf-8')

    def read(self):
        # 返回读取的文件
        return self.file.read()

    def __del__(self):
        self.file.close()


file = File('a.txt')
print(file.read())
file .__del__()
print(file.read()) # 报错显示文件已经被关闭

PS:上述可以通过del删除非解释器的资源

 

(5)call

作用:在调用对象的时候被执行

例如:

class A:
    def __call__(self, *args, **kwargs):
        print("call run")
        print(args)
        print(kwargs)


a = A()
a(18,a = 100)

 

(6)solts

作用:

  (1)一种优化机制 防止浪费不必要的内存

  (2)其将不固定的属性数量变的固定了

  (3)这样解释器不会为对象创建名称空间 减少了__dict__

  (4)当类中出现了该参数 对象也不能在添加属性

例如:

import sys
class Person:
    __slots__ = ['name']

    def __init__(self,name):
        self.name = name

p = Person('SR')
# print(p.__dict__) # 报错

# 加slots之前
print(sys.getsizeof(p)) # 56

# 加slots
print(sys.getsizeof(p)) # 48

# 添加新属性
p.age = 20 # 报错

 

(7)

(1)getattr

  作用:当用点访问属性的时候 如果属性不存在则会执行

(2)setattr

  作用:当用点设置属性的时候 会执行改函数

(3)delattr

  作用:用del 删除属性的时候 会执行改函数

(4)getattribute

  作用:当在调用属性的时候 如果属性存在则会调用该函数并且将属性值返回 如果属性不存在的情况下则会调用getattr

例如:

class A:

    def __setattr__(self, key, value):

        print("__setattr__")
        self.__dict__[key] = value

    def __delattr__(self, item):
        print("__delattr__")
        self.__dict__.pop(item)


    def __getattr__(self, item):
        print("__getattr__")
        return 1

    def __getattribute__(self, item):
        print("__getattribute__")
        # return self.__dict__[item]
        return super().__getattribute__(item)
方法演示

PS:

(1)当在__getattribute__代码块中,再次执行属性的获取操作时,会再次触发__getattribute__方法的调用,代码将会陷入无限递归,直到Python递归深度限制(重载__setter__方法也会有这个问题)

(2)为了避免无限递归,应该把获取属性的方法指向一个更高的超

 

(8)

(1)getitem

  作用:当使用[]调用属性的时候会执行该函数

(2)setitem

  作用:当使用[]设置属性的时候 会执行该函数

(8)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"])

 

(9)运算符重载:

作用:

(1)当在python中调用某个符号的时候 python都会为该符号定义一个含义 并且调用该含义背后所对应的函数

(2)当我们需要自己定义比较规则的时候 就可以自己在子类中覆盖父类中所对应的 大于 等于 小于等方法

例如:

class Student(object):
    def __init__(self,name,height,age):
        self.name = name
        self.height = height
        self.age = age

    def __gt__(self, other):
        # print(self)
        # print(other)
        # print("__gt__")
        return self.height > other.height
    
    def __lt__(self, other):
        return self.height < other.height

    def __eq__(self, other):
        if self.name == other.name and  self.age == other.age and self.height == other.height:
            return True
        return False

stu1 = Student("jack",180,28)
stu2 = Student("jack",180,28)
# print(stu1 < stu2)
print(stu1 == stu2)

PS:

(1)gt 大于 lt 小于 eq等于

(2)在代码中other指的是其余对象 self作为本身

 

(9)上下文管理:

(1)在生活中一段话的意义要看情景 上问和下文有关联

(2)在python中上下文可以看做一个范围 某些代码只在一个范围内有效

  (1)enter 进入上下文

  (2)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...")
        # print(exc_type,exc_val,exc_tb)
        self.file.close()
        return True

(1)代码执行完毕之后 执行exit结束上下文

(2)代码执行错误也会执行exit结束上下文

(3)其会返回错误类型 错误的信息 以及错误的路径追踪信息

 

PS:

(1)enter返回值为对象自己

(2)exit返回值为布尔值 表示错误信息是否被处理 如果为真则表示已经处理 为假则未处理

 

posted @ 2019-07-29 23:15  SR丶  阅读(208)  评论(0编辑  收藏  举报