zoukankan      html  css  js  c++  java
  • 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('硬盘剩余不足
    ')
    定制文件写操作
  • 相关阅读:
    简明Python3教程 12.问题解决
    简明Python3教程 11.数据结构
    【SPOJ 694】Distinct Substrings
    【codeforces Manthan, Codefest 17 C】Helga Hufflepuff's Cup
    【CF Manthan, Codefest 17 B】Marvolo Gaunt's Ring
    【CF Manthan, Codefest 17 A】Tom Riddle's Diary
    【SPOJ 220】 PHRASES
    【POJ 3261】Milk Patterns
    【POJ 3294】Life Forms
    【POJ 1226】Substrings
  • 原文地址:https://www.cnblogs.com/sunjinchao/p/11108370.html
Copyright © 2011-2022 走看看