多态 鸭子类型 反射 内置方法(__str__,__del__) 异常处理

'''
1什么是多态
    多态指的是同一种/类事物的不同形态

2 为何要有多态
    多态性:在多态的背景下,可以在不用考虑对象具体类型的前提下而直接使用对象
    多态性的精髓:统一
    多态性的好处:
        1增加了程序的灵活性:
            以不变应万变,不论对象千变万化,使用者都是同一种形式去调用
        2增加了程序可扩展性
            继承一个Animal类创建一个新的类,使用者无需更改自己的代码,还是用原来的方式调用
3 如何用多态

'''
'''
class Animal:
    def speak(self):
        pass

class People(Animal):
    def speak(self):
        print('say hello')

class Dog(Animal):
    def speak(self):
        print('wang wang wang')

class Pig(Animal):
    def speak(self):
        print('哼哼哼')

obj1=People()
obj2=Dog()
obj3=Pig()

# obj1.speak()
# obj2.speak()
# obj3.speak()


def speak(animal):
    animal.speak()

speak(obj1)
speak(obj2)
speak(obj3)
# say hello
# wang wang wang
# 哼哼哼


多态性带来的好处,比如python的系列类型有多种形态:字符串,列表,元组,多态性提现下

s1='hello'
l1=[1,2,3]
t1=(1,2)

我们可以在不考虑三者类型的前提下使用是 s l t
print(len(s1)) #s1.__len__()
print(len(l1)) #l1.__len__()
print(len(t1))  #t1.__len__()

'''
# import abc
#
#
# class Animal(metaclass=abc.ABCMeta):
#     @abc.abstractmethod
#     def speak(self):
#         pass
#
#     @abc.abstractmethod
#     def run(self):
#         pass


# Animal() 父类只是用来建立规范的,不能用来实例化的,更无须实现内部的方法
# 只是规定有这些方法或者属性 具体属性或者方法在子类中具体实现
# class People(Animal):
#     def speak(self):
#         print('say hello')
#
#     def run(self):
#         pass
#
#
# class Dog(Animal):
#     def speak(self):
#         print('汪汪汪')
#
#     def run(self):
#         pass
#
#
# class Pig(Animal):
#     def speak(self):
#         print("哼哼哼")
#
#     def run(self):
#         pass
#
#
# obj = People()
# obj2 = Dog()
# obj3 = Pig()


# 上面是强制性的,父类有的方法,子类必须有

# obj.speak()
# obj2.speak()
# obj3.speak()
# say hello
# 汪汪汪
# 哼哼哼

# python 崇尚鸭子类型
# 利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法
# class Disk:
#     def read(self):
#         print('Disk read')
#
#     def write(self):
#         print('Disk write')
#
#
# class Memory:
#     def read(self):
#         print('Mem write')
#
#     def write(self):
#         print('Mem write')
#
#
# class Cpu:
#     def read(self):
#         print('Cpu read')
#
#     def write(self):
#         print('Cpu write')


# obj=Disk()
# obj2=Memory()
# obj3=Cpu()
#
# obj.read()
# obj2.read()
# obj3.read()

# Disk read
# Mem write
# Cpu read


# 反射: 通过字符串来反射/映射到对象/类的属性上
#         (之前是 xx.属性来映射或反射到类或对象的属性上)
# class People:
#     def __init__(self,name,age):
#         self.name=name
#         self.age=age
#     def run(self):
#         print('%s is running' %self.name)
#
#
# obj=People('egon',18)

# print(obj.__dict__) #{'name': 'egon', 'age': 18}
# print(obj.name) #obj.__dict__['name']  #egon
# obj.name="EGON" #obj.__dict__['name']="EGON"
# del obj.name  #del obj.__dict__['name']
# print(obj.__dict__) #{'age': 18}
# obj.sex='male' #obj.__dict__['sex']='male'

# print(hasattr(obj, 'name')) #True  'name' in obj.__dict__

# print(getattr(obj, 'name'))  #拿到值egon obj.__dict__['name']
# print(getattr(obj, 'xx', None))  #拿值 没有则返回None obj.__dict__['xx']

# setattr(obj, 'name', 'EGON')  #obj.__dict__['name']='EGON'  #EGON 有name就改值
# setattr(obj,'xxx','2222') #{'name': 'egon', 'age': 18, 'xxx': '2222'}  没有就创建
# print(obj.name)
# print(obj.__dict__)

# delattr(obj,'name')
# print(obj.__dict__)  #{'age': 18}

# import os
# os.remove
# print(hasattr(os,'remove'))  #True


# class Ftp:
#     def get(self):
#         print('get')
#     def put(self):
#         print('put')
#
#     def login(self):
#         print('login')
#
#     def run(self):
#         while True:
#             cmd=input(">>>: ").strip()  #cmd='get'
#             if hasattr(self,cmd): #cmd in self.__dict
#                 method=getattr(self,cmd) #self.__dict__['cmd']
#                 method()
#
#             else:
#                 print('输入方法不存在')
#
#
# obj=Ftp()
# obj.run()


# 内置方法:
# __str__:在对象被打印时自动触发,可以用来定义对象被打印时的输出信息
# 注意:必须返回一个字符串类型的值
# class People:
#     def __init__(self,name,age):
#         self.name=name
#         self.age=age
#
#     def __str__(self):
#         # print('run.....')
#         return  'name: %s age:%s'%(self.name,self.age)
# obx=People('egon',18)
# print(obx)   #print(obx.__str__())
# name: egon age:18

# obj1=list([1,2,3])
# print(obj1)  #[1, 2, 3]


# __del__:在对象被删除时先自动触发该方法,可以用来回收对象以外其他相关资源,比如系统资源
# class Foo:
    # def __init__(self,x,filepath,encoding='utf-8'):
    #     self.x=x
    #     self.f=open(filepath,'rt',encoding=encoding)
    #
    # def __del__(self):
    #     print('run.....')
    #     #回收对象关联的其他资源
    #     self.f.close()

# obj=Foo(1,'a.txt')
# print('========》') 1程序结束了会把占用的内存空间回收掉 删除对象 最后执行__del__回收对象关联的其他资源
    # ========》
    # run.....


# obj=Foo(1,'a.txt')  #程序没结束提前删除 会先执行__del__ 回收对象关联的其他资源
# del obj
# print('========》')
    # run.....
    # ========》


'''
1 什么是异常处理
    异常是错误发生的信号,一旦程序出错就会产生一个异常,如果该异常
    没有被应用程序处理,那么该异常就会被抛出来,程序的执行也随之终止
    
    异常包含三个部分:
        1 traceback异常的追踪信息
        2 异常的类型
        3 异常的信息
    
    错误分为两大类:
        1 语法上的错误:在程序运行前就应该立即修正
        2 逻辑上的错误
    
2 为和要有异常处理
    避免程序因为异常而崩溃,所以在应用程序中应该对异常进行处理,从而增强程序的健壮性

3 如何异常处理
try:
    代码1 
    代码2   #抛出一种异常    #!!!!下面代码块不会执行
    代码3
    。。。
except NameError:   #捕获异常也只会捕获一种异常下面的except分支不会执行(像if 。。elif...一样)
    当抛出的异常是NameError时执行的子代码块
except....:    
    pass
except...:
    pass
else:         
    pass    #else的子代码块会在被检测的代码块没有异常的情况下执行
finally:   
    pass     #无论被检测的代码有没有异常都会执行

'''
# 语法错误
# print('asdjfkj'
# 1 常见的逻辑错误导致的异常
# age=input('>>: ').strip()
# print(age>10)    #TypeError

# for  i in  10: #TypeError
#     pass
# import os  #AttributeError
# os.xxx
# 1/0  #ZeroDivisionError

# print('====1')
# print('====2')
# print('====3')
# # l=[1,2,3]
# # l[100]   #IndexError
# print('====4')
# # d={'x':1,'y':2}
# # d['z']     #KeyError
# print('====5')

# 2.异常处理
# 异常处理的单分支
# try:
#     print('=====1')
#     print('=====2')
#     print('=====3')
#     d = {'x': 1, 'y': 2}
#     d['z']  # KeyError
#     print('=====4')
#     l = [1, 2, 3]
#     l[1000]  # IndexError
#     print('=====5')
# except IndexError:
#     print('IndexError')
# print('other code')

# 异常处理的多分支
# try:
#     print('=====1')
#     print('=====2')
#     print('=====3')
#     d = {'x': 1, 'y': 2}
#     d['z']  # KeyError
#     print('=====4')
#     l = [1, 2, 3]
#     l[1000]  # IndexError
#     print('=====5')
# except KeyError as e:
#     print('KeyError',e)
# except IndexError as e:
#     print('IndexError',e)
#
# print('other code')

# try:
    # print('=====1')
    #     print('=====2')
    #     print('=====3')
    #     d = {'x': 1, 'y': 2}
    #     # d['z']  # KeyError
    #     print('=====4')
    #     l = [1, 2, 3]
    #     l[1000]  # IndexError
    #     print('=====5')
    # except (KeyError,IndexError) as e: #except(里面多个错误捕获类型)
    #     print(e)
    # print('other code')

# 万能异常类型Exception:可以匹配任意类型的异常
# try:
#     print('=====1')
#     print('=====2')
#     print('=====3')
#     d = {'x': 1, 'y': 2}
#     # d['z']  # KeyError
#     # xxx
#     print('=====4')
#     l = [1, 2, 3]
#     l[1000]  # IndexError
#     print('=====5')
# except IndexError as e:
#     print('IndexError:', e)
# except KeyError as e:
#     print('KeyError:', e)
# except Exception as e:
#     print('Exception:',e)
#
# print('other code')

# 主动触发异常
# print('===>1')
# print('===>2')
# raise TypeError('类型错误')   #运行到这里就报错
# print('===>3')

# class People:
#     def __init__(self,name,age):
#         self.__name=name
#         self.__age=age
#
#     def tell_info(self):
#         print(self.__name,self.__age)
#
#     def set_info(self,name,age):
#         if not isinstance(name,str):
#             raise TypeError('名字必须是str类型')
#         if not isinstance(age,int):
#             raise TypeError('年龄必须是int类型')
#         self.__name=name
#         self.__age=age

# obj=People('egon',18)
# print(obj.__dict__)  # {'_People__name': 'egon', '_People__age': 18}
# obj.tell_info()  #egon 18

# obj.set_info('alex',123)
# obj.tell_info()  #alex 123

# 自定义异常类型(了解)
# class MyException(BaseException):
#     def __init__(self,msg):
#         super().__init__()
#         self.msg=msg
#
#     def __str__(self):   #在对象被打印时自动触发,可以用来定义对象被打印时的输出信息
#         return '<%s>'%self.msg
#
# raise MyException('我自定义的异常')
# # __main__.MyException: <我自定义的异常>

# 断言
print('上半部分,生产数据')
l=[1,2,3,4,5]

# if len(l)!=5:  #满足条件执行里面的 主动触发异常 下面代码不执行
#     raise TypeError('类表长度必须为5')
assert  len(l)==5   #相当于门槛,满足条件才执行下面的代码
#AssertionError

print('下半部分,处理数据')

封装:封装的真谛在于明确地区分内外,封装的属性可以直接在内部使用,而不能被外部直接使用,然而定义属性的目的终归是要用,外部想要类隐藏的属性,需要我们为其开辟接口,让外部能够间接地用到我们隐藏起来的属性,意义:

  1封装数据:将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加对数据的操作限制,以此完成对数据属性操作的严格控制。

class Teacher:
    def __init__(self,name,age):
        # self.__name=name
        # self.__age=age
        self.set_info(name,age)

    def tell_info(self):
        print('姓名:%s,年龄:%s' %(self.__name,self.__age))
    def set_info(self,name,age):
        if not isinstance(name,str):
            raise TypeError('姓名必须是字符串类型')
        if not isinstance(age,int):
            raise TypeError('年龄必须是整型')
        self.__name=name
        self.__age=age


t=Teacher('egon',18)
t.tell_info()

t.set_info('egon',19)
t.tell_info()
View Code

  2封装方法:目的是隔离复杂度

    在编程语言里,对外提供的接口(接口可理解为一个入口),可以是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。

#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
#隔离了复杂度,同时也提升了安全性

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print_bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')

    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()

隔离复杂度的例子
View Code

  3在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

#正常情况
>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B
 

#把fa定义成私有的,即__fa
>>> class A:
...     def __fa(self): #在定义时就变形为_A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A
View Code

 

隐藏:在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

  这仅仅只是一种变形操作且仅仅只在类定义阶段发生变形

  类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式。

 

__delattr__() 删除属性前进行的操作需要继承super().__delattr__(属性)否则删除不了

__del__() 删除对象前进行的操作 释放和对象相关的其他资源

__delete__()删除对象的属性(属性是组合类型的 一个类的对象作为另外一个类的属性)

posted @ 2019-04-22 22:58  读自己  阅读(191)  评论(0编辑  收藏  举报