• Day 20: 面向对象【多态,封装,反射】字符串模块导入/内置attr /包装 /授权


    面向对象,多态:

    有时一个对象会有多种表现形式,比如网站页面有个按钮, 这个按钮的设计可以不一样(单选框、多选框、圆角的点击按钮、直角的点击按钮等),尽管长的不一样,但它们都有一个共同调用方式,就是onClick()【鼠标单击】方法。我们直要在页面上一点击就会触发这个方法。点完后有的按钮会变成选中状态、有的会提交表单、有的甚至会弹窗。这种多个对象共用同一个接口,又表现的形态不一样的现象,就叫做多态( Polymorphism )。

    例如:人会吃,猪也会吃,牛也会吃,那都是吃,这吃就是一个接口,但是,每个吃的方式又不一样。多个对象共用一个接口就是多态

     1 #我们定义一个车类,他们都有共同的方法,启动和刹车。
     2 #但是不同的车的启动方法不一样,比如说,卡车可能用钥匙启动,跑车电子启动。
     3 #刹车的时候,跑车直接刹车就好了,但是卡车有时候就不敢直接刹车需要点刹
     4 
     5 class Car:#定义一个车类
     6     def __init__(self, name):
     7         self.name = name
     8     def drive(self):
     9         raise NotImplementedError("子类必须实现抽象方法")#异常处理后面说
    10         #意义就是,你可以调用我得方法,但是子类必须自行实现自己得方法,不然就报错
    11     def stop(self):
    12         raise NotImplementedError("子类必须实现抽象方法")
    13 class SportsCar(Car):#跑车类继承车类
    14     #继承父类的init方法
    15     def drive(self):
    16         return '开动'
    17     def stop(self):
    18         return '点刹'
    19 class Truck(Car):#卡车继承车类
    20     #继承父类的init方法
    21     def drive(self):
    22         return '卡车开得慢是因为负载过重.'
    23     def stop(self):
    24         return '装有钢管,不敢直接刹车,不然车头不见啦!'
    25 
    26 # cars = [Truck('东风重卡'),
    27 #         Truck('三一重工'),
    28 #         SportsCar('法拉利')]
    29 
    30 cars = Truck('东风卡车')
    31 cars1 = SportsCar('法拉利')
    32 print(cars.stop())#装有钢管,不敢直接刹车,不然车头不见啦!
    33 print(cars1.stop())#点刹
    34 #这2个实例都使用的共同的方法
    35 # for car in cars:
    36 #     print(car.name + ': ' + car.drive())

    封装:

    封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制。封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让程式码更容易理解与维护,也加强了代码数据的安全性。

    优点:

    1. 良好的封装能够减少耦合。

    2. 类内部的结构可以自由修改。

    3. 可以对成员变量进行更精确的控制。

    4. 隐藏信息,实现细节。

    在参数里面 加上__ 双下划线 ,就是实现了封装属性

    #如果你定义一个类之后,有的参数不想让人直接调用,或者修改的话,就需要封装了
    class Room:#定义个房子类
        def __init__(self,name,owner,width,length,high):
            self.name=name
            self.owner=owner
            self.__width=width# 在变量前面 加__ 2个下划线就把数据属性封装了。再实例中就不可以直接调用了也不能修改了
            self.__length=length
            self.__high=high
    
        def tell_area(self): #此时我们想求的是面积
            return self.__width * self.__length *self.__high
    
        def tell_width(self):#这样函数外面就可以调用了
            return self.__width
    
    
    r1=Room('卫生间','alex',100,100,10000)
    print(r1.name)#这个参数没有封装,所以可以直接调用
    r1.name = '卧室'
    print(r1.name)#也可以修改
    # r1.width# 这样就不能调用,报错哦
    r1.tell_width() #这个实际上在调用函数的方法调用到了width的值
    1 #在python的一个约定,一般单下滑线的变量,一般不希望调用。但是不限制你调用,你想调用也行。
    2 #使用者碰到定义者用_线写得变量,经量还时不要调用

     类的反射:主要指陈旭可以访问、检测和修改他本身状态或者行为的一种能力

    下列方法适用于类和对象

    hasattr(OBJ,name): 判断一个对象里面有没有这个属性name(字符串)

    #判断OBJ中有没有一个name字符串对应的方法或者属性

    getattr,

    #获取一个类的的属性

    setattr:设置实例属性

    delattr: 删除

    class Person:#定义一个人类
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def say_hi(self):
            print("hi,honey , my name is " ,self.name)
    obj=Person('SJC',26)
    #检测是否含有某属性
    print(hasattr(obj,'name'))#检查有没有这个变量
    print(hasattr(obj,'say_hi'))#检查有没有这个字符串
    #获取属性
    n=getattr(obj,'name')
    print(n)
    func=getattr(obj,'say_hi')
    func()
    print(getattr(obj,'aaaaaaaa','不存在啊')) #后面可以加参数,如果不存在就报错
    #设置属性
    setattr(obj,'XFD',"girl")#设置实例属性
    setattr(obj,'show_name',lambda self:self.name+'--%s' % self.age)#设置函数属性
    print(obj.__dict__)
    print(obj.show_name(obj))#必须添加一个参数
    # #删除属性
    delattr(obj,'age')
    delattr(obj,'show_name')
    #delattr(obj,'show_name111') # 不存在,则报错
    print(obj.__dict__)
    Hasattr/getattr/delattr/setattr

    动态导入模块:__import__#  如果是多目录导入,导入的要写路径

     m = __import__('test1111')#模块路径 m.sun()#执行函数 

    #如果一个函数名以单下划线开头  那导入模块的时候,默认不会导入,使用的时候也要加上_单下划线

    动态导入模块1:importlib  

     import importlib m = importlib.import_module("test1111") 

    #这个方式是导入的顶级模块,直接m.就可以运行

     内置:__setattr__、__deklattr__、__getattr__,定义到类中

    class Person:#定义一个人类
        gender = "man"
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def __getattr__(self, item):
            print("执行__getattr__")
        def __delattr__(self, item):
    # self.__dict__.pop(item)系统应该是这么操作的
    print("执行__delattr__") def __setattr__(self, key, value): # self.key = value#RecursionError: maximum recursion depth exceeded #进入递归 self.__dict__[key] = value #所有的设置属性,都是在调用属性字典 print("执行__setattr__") def say_hi(self): print("hi,honey , my name is " ,self.name) obj=Person('SJC',26) # print(obj.name)#SJC # print(obj.alkf)#执行__getattr__ #__getattr__调用不存在的属性时触发 # del obj.age #执行__delattr__ # del obj.gender#执行__delattr__ #删除时,执行__delattr__ obj.NB = "XFD" #设置成功 print(obj.__dict__)

    #这些都是内置的,如果你自己在自己得类中定义了,然就使用你自己定义的。如果没定义,那就使用系统内置的

    #__delattr__setattr__ 不经常用

    __getattr__的用法

     1 class Person:#定义一个人类
     2     gender = "man"
     3     def __init__(self,name,age):
     4         self.name = name
     5         self.age = age
     6     # def __getattr__(self, item):
     7     #     return "你找的属性【%s】不存在" % item
     8     # def __delattr__(self, item):
     9     #     print("执行__delattr__")
    10     def __setattr__(self, key, value):
    11     #     self.__dict__[key] = value
    12         print("执行__setattr__")
    13     def say_hi(self):
    14         print("hi,honey , my name is " ,self.name)
    15 obj=Person('SJC',26)
    16 # print(obj.name)#SJC
    17 # print(obj.ada)#你找的属性【ada】不存在 #触发getattr
    __getattr__用法

    __setattr__用法:

    需求:设置的值都为字符串。

     1 class Person:#定义一个人类
     2     gender = "man"
     3     def __init__(self,name):
     4         self.name = name
     5     def __setattr__(self, key, value):
     6         if type(value) is str:
     7             self.__dict__[key] = value
     8             return "设置成功"
     9         else:
    10             print('设置失败')
    11 
    12 obj=Person(123)#
    13 # print(obj.name)
    _setattr__

    __delattr__ 就不用演示啦

    包装内置方法:使用继承

    备注:我们可以用用继承的方式来修改自定义 的一些方法。

    例如:你想修改内置的list方法 ,你可以定义一个LIST 类,然后设置各类函数,比如定义一个,append 的类方法append只能添加字符串类型,然后再用上__setattr__  就可以自己定义功能了。【继承方法】

    #class List(list):

    授权:也是包装的一个特性。但是使用的是__getattr__。不用继承

    例:定制自己文件操作时的写   方法,写入文本的时候,加入时间 别的方法不变。

    import time
    class FileHandle:
        def __init__(self,filename,mode='r',encoding='utf-8'):
            #默认参数,不填使用默认的。
            # self.filename=filename
            self.file=open(filename,mode,encoding=encoding)
            self.mode = mode
            self.encoding = encoding
        def write(self,line):
    
            #line 就是你调用write写入的值
            t=time.strftime('%Y-%m-%d %X')#定义时间格式
            self.file.write('%s %s' %(t,line))#T时间,line写入的内容
            #在写入时自动加上时间
        def __getattr__(self, item):
            # print(item,type(item))
            # self.file.read
            return getattr(self.file,item)
            #因为item传进来,是个字符串,getattr的功能就是获取字符串功能参数是字符串
    #你在实例化的时候,传入的时候,没有那个值,就是触发getattr.
    #出入getattr之后,我们返回file.那就启动了init的方法
    
    f1=FileHandle('a.txt','w+')
    print(f1.file)
    print(f1.__dict__)
    print('==>',f1.read) #触发__getattr__
    print(f1.write)
    #f1.read执行后,然后系统会寻找init,init没有,去找类,类也没有,就出发_getattr_然后使用系统内置的open
    #f1.write执行后,系统寻找init,没有,找类,类有write方法,write方法,返回
    f1.write('cpu负载过高
    ')
    f1.write('内存剩余不足
    ')
    f1.write('硬盘剩余不足
    ')
    定制文件写操作
  • 相关阅读:
    通联支付相关注意事项
    账号配置vue版本的扫码下单以及对店铺进行装修的步骤
    银盒子扫码下单在线订单开启商品售卖时段使用说明
    ERP承接新后台优惠规则问题
    简易付安装后无法使用
    ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证代码篇
    ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证
    ASP.NET没有魔法——ASP.NET MVC 过滤器(Filter)
    ASP.NET没有魔法——ASP.NET Identity与授权
    ASP.NET没有魔法——ASP.NET Identity的加密与解密
  • 原文地址:https://www.cnblogs.com/sunjinchao/p/11108370.html
Copyright © 2020-2023  润新知