• 饮冰三年-人工智能-Python-18Python面向对象


    1 类与实例对方法和属性的修改

    class Chinese:
        # 这是一个Chinese的类
        #定义一个类属性,又称为静态数据或者静态变量,相当于C#中的static
        country="China"
        # 定义一个初始化函数,
        def __init__(self,name,age,gender):
            self.name=name
            self.age=age
            self.gender=gender
        #定义一个方法
        def play(self,ballName):
            print('%s 正在打 %s' %(self.name,ballName))
    
    #1类属性
    print("----------开始修改类属性")
    #1.1 查看类属性
    print(Chinese.country) #China
    #1.2 修改类属性
    Chinese.country="中华人民共和国"
    print(Chinese.country) #中华人民共和国
    #1.3 删除类属性
    del Chinese.country
    print(Chinese.__dict__)
    #{'__module__': '__main__', '__init__': <function Chinese.__init__ at 0x0000000001D30EA0>, 'play': <function Chinese.play at 0x000000000247C7B8>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None}
    #1.4 添加类属性
    Chinese.country="中国"
    print(Chinese.__dict__)
    #{'__module__': '__main__', '__init__': <function Chinese.__init__ at 0x0000000002300EA0>, 'play': <function Chinese.play at 0x000000000250C7B8>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None, 'country': '中国'}
    
    #2方法属性
    print("----------开始修改方法属性")
    #2.1 查看方法属性
    p1=Chinese('张三',18,"")
    Chinese.play(p1,'篮球') #张三 正在打 篮球
    #2.2 修改方法属性
    def play(self,ballName,address):
        print('%s 在%s打%s' %(self.name,address,ballName))
    Chinese.play=play
    Chinese.play(p1,'篮球','操场') #张三 在操场打篮球
    #2.3 删除类属性
    del Chinese.play
    print(Chinese.__dict__)
    #{'__module__': '__main__', '__init__': <function Chinese.__init__ at 0x0000000001D40EA0>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None, 'country': '中国'}
    #2.4 添加方法
    def eat(self,food):
        print("%s 正在吃 %s" %(self.name,food))
    Chinese.eat=eat
    print(Chinese.__dict__)
    # {'__module__': '__main__', '__init__': <function Chinese.__init__ at 0x0000000001D40EA0>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None, 'country': '中国', 'eat': <function eat at 0x0000000001DFC7B8>}
    
    #3实例类属性
    print("----------开始修改实例类属性")
    #3.1 查看实例类属性
    p=Chinese('张三',18,"")
    print(p.country) #中国
    #3.2 修改实例类属性
    p.country="中华人民共和国"
    print(p.country) #中华人民共和国
    #3.3 删除实例类属性
    del p.country
    print(p.__dict__)
    #{'name': '张三', 'age': 18, 'gender': '男'}
    # 3.4 添加类属性
    p.country="中国"
    print(p.__dict__)
    #{'name': '张三', 'age': 18, 'gender': '男', 'country': '中国'}
    
    print("----------开始修改实例属性")
    #4.1 查看实例类属性
    p=Chinese('张三',18,"")
    print(p.name) #张三
    #4.2 修改实例类属性
    p.name="张三三"
    print(p.name) #张三三
    #4.3 删除实例类属性
    del p.name
    print(p.__dict__)
    #{'age': 18, 'gender': '男'}
    # 4.4 添加类属性
    p.name="张三三"
    print(p.__dict__)
    #{'age': 18, 'gender': '男', 'name': '张三三'}
    
    print("----------开始修改实例方法")
    #4.1 查看实例方法
    p=Chinese('张三',18,"")
    p.eat('包子')
    # 张三 正在吃 包子
    #4.2 修改实例类属性
    def eat(self,food,address):
        print('%s在%s吃%s' %(self.name,address,food))
    p.eat=eat
    p.name="张三三"
    p.eat(p,"包子","食堂") #张三三在食堂吃包子
    #4.3 删除实例类属性
    del p.eat
    print(p.__dict__)
    #{'name': '张三三', 'age': 18, 'gender': '男'}
    # 4.4 添加实例方法属性
    def study(self,cont):
        print('%s学%s' % (self.name,cont))
    p.study = study
    p.study(p,'python')
    print(p.__dict__)
    #张三三学python
    # {'name': '张三三', 'age': 18, 'gender': '男', 'study': <function study at 0x0000000002526B70>}
    ViewCode

      类是什么时候被加载的,以及类名是什么时候生效的?

        创建一个类的空间,然后从上到下加载内容(属性、方法)。然后把这个命名空间指向类名。

      

       为什么Chinese.play与p.play的内存地址不一样?

        p.play其实存的不是func的内存地址,而是存着func内存地址的一个变量的地址。类似:Chinese.play存的是你的家庭地址。而p.play存的是地址簿的第二页。    

    2 静态属性、静态方法、类方法

    class Room:
        owner="China"
        # 这是一个房间的类
        def __init__(self,name,width,length,height):
            self.name=name
            self.width=width
            self.length =length
            self.height=height
        @property
        # 这是一个方法,但是通过@property装饰后,就变成了一个静态方法,可以通过.方法名调用
        def getArea(self):
            return self.width*self.length
        @classmethod
        # 这是一个方法,但是通过@classmethod装饰后,就变成了一个类方法,可以类调用,不用实例化
        def getOwner(cls):
            print("房产所有者"+cls.owner)
        @staticmethod
        # 这是一个方法,但是通过@staticmethod装饰后,就变成了一个静态方法,可以在调用处直接传递参数
        # 用户输入想要的面积和折扣,可以计算出价格
        def getPrice(area,discount):
           return area*20000*discount/10
    
    r1=Room("天字一号房",10,20,2)
    print('房间面积'+str(r1.getArea)) #房间面积200
    #类方法:可以通过类名直接调用方法
    Room.getOwner() #房产所有者China
    #静态方法,可以传递一些与类关联不大的数据
    print(r1.getPrice(r1.getArea,9)) #3600000.0
    View Code

    总结:

    静态属性 @property 静态方法 @staticmethod 类方法 @classmethod
    只读的,可以当属性使用
    和类有关,和参数关系不密切
    一个cls参数

    实例.func

    实例.func() 类.func(),类实例.func()

    3 组合(大类包含小类) 什么有什么的关系

    class School:
        # 这是一个学校类
        def __init__(self,name,address):
            self.name=name
            self.address=address
    class Courses:
        # 这是一个课程类,组合了一个学校
        def __init__(self, name, cycle,price,schoolObj):
            self.name = name
            self.cycle = cycle
            self.price = price
            self.school = schoolObj
        def getInfo(self):
            print('%s 正在开设 %s' %(self.school.name,self.name))
    school = School('北大','北京')
    Courses('python','100','10',school).getInfo()
    View Code

    4 继承(子类继承父类) 什么是什么的关系

    #继承一:抽象出共有的父类,实现继承
    class Animal:
        def __init__(self,name):
            self.name=name
        def eat(self):
            print('%s会吃' %(self.name))
        def bark(self):
            print('%s会叫' %self.name)
    class Dog(Animal):
        pass
    class Cat(Animal):
        pass
    
    dog=Dog("小黄")
    dog.bark()
    cat = Cat("伊丽莎白")
    cat.eat()
    #继承二:但是猫和狗的叫声不同,所以常用的是接口继承(父类只提供一个规范,子类在调用时需要实现这些规范)
    # 如果是抽象方法,子类必须实现
    import abc
    class Animal(metaclass=abc.ABCMeta):
        def __init__(self,name):
            self.name=name
        @abc.abstractclassmethod
        def eat(self):
            print('%s会吃' %(self.name))
        def bark(self):
            print('%s会叫' %self.name)
    class Dog(Animal):
        def bark(self):
            print('%s会汪汪叫' %self.name)
        #如果是抽象方法,子类必须实现
        def eat(self):
            pass
    class Cat(Animal):
        def eat(self):
            print('%s会吃鱼儿' %self.name)
    
    dog=Dog("小黄")
    dog.bark()
    cat = Cat("伊丽莎白")
    cat.eat()
    两种继承方式

      4.1 继承顺序

      当类是经典类(class C1:)时,多继承情况下,深度优先(依次找到根节点)

      当类是新式类(class C1(object):)时,多继承情况下,广度优先(最后一次才找到根节点)

      原理:python会计算一个方法解析顺序(MRO)列表,可通过print(类名.__mro__)查看

      4.2 子类中调用父类的方法

    class Vehicle:
        def __init__(self,name,speed,load):
            self.name=name
            self.speed = speed
            self.load = load
        def run(self):
            print('%s开始启动' %(self.name))
    
    class Subway(Vehicle):
        def __init__(self,name,speed,load,line):
            Vehicle.__init__(self,name,speed,load)
            self.line = line
        def run(self):
            Vehicle.run(self)
            print("时速:"+self.speed)
    class Car(Vehicle):
        # 使用super减少了self字段的传递,而且如果父类类名修改的话,子类继承不用改变
        def __init__(self,name,speed,load,brand):
            super().__init__(name,speed,load)
            self.brand = brand
        def run(self):
            super().run()
            print("品牌:"+self.brand)
    
    #测试数据
    sub=Subway("地铁","300km/h","20000","2号线")
    sub.run()
    
    cr=Car("汽车","80km/h","5","红旗")
    cr.run()
    两种方式实现继承

     5 多态

      类的继承有两成意义:改变+扩展。多态就是累的这两层意义的一个具体的实现机制。在不考虑实例(子类)类型的情况下,使用子类。即调用不同的实例化对象下的相同方法,时间的过程不同

    class H2O:
        def __init__(self,name,temp):
            self.name=name
            self.temp = temp
        def currentStatus(self):
            if self.temp < 0:
                print("在101.325kPa下,当前状态为:冰")
            elif self.temp == 0:
                print("在101.325kPa下,当前状态可能是:冰水混合物")
            elif self.temp < 100:
                print("在101.325kPa下,当前状态为:水")
            elif self.temp > 100:
                print("在101.325kPa下,当前状态为:水蒸气")
    class Ice(H2O):
        pass
    class Water(H2O):
        pass
    class Steam(H2O):
        pass
    
    ice = Ice("",-10)
    water = Water("",10)
    steam= Steam("水蒸气",101)
    
    ice.currentStatus();water.currentStatus();steam.currentStatus();
    水的三种状态

     6 封装 明确区分内外,其实不能真正不被外部访问。内部实现逻辑,外部无需知晓,并且为封装到内部的逻辑提供一个供外部访问的接口  

     约定:_开头定义

     __开头,其实在外部调用的时候python默认修改了名“_类名_定义名“

    class People:
        _plate="地球"
        def __init__(self,name,age):
            self.name=name
            self._age=age
    
    p=People("张三",12)
    print(p._plate) #地球
    print(p._age)   #12
    '''虽然以_开头但是还可以被访问到,因为这只是一种约定'''
    class People2:
        __plate="地球"
        def __init__(self,name,age):
            self.name=name
            self.__age=age
    
    p=People2("张三",12)
    #print(p.__plate) #报错 AttributeError: 'People2' object has no attribute '__plate'
    print(p._People2__plate)  #地球
    print(p._People2__age)   #12
    '''虽然以__开头不可以被直接访问到,但可以通过“_+类名+自定义名称'''
    class People3:
        __plate="地球"
        def __init__(self,name,age):
            self.name=name
            self.__age=age
        # 外部现在是无法通过属性名调用了,但是目前有一个需求:就是要获取年龄,这个时候还可以通过定义接口的方法实现
        def getAge(self):
            return self.__age;
    p3=People3("张三",12)
    print(p3.getAge())
    View Code

    没有必要的封装,不可取

    7 反射:自省,自己检测自己。主要指程序可以访问、检测和修改它本身状态或行为的一种能力。

        用字符串类型的变量名来访问变量值。类似XX.YY 这种形式,都可以通过反射来访问。类、对象、模块

    # 反射:自省,自己检测自己。主要指程序可以访问、检测和修改它本身状态或行为的一种能力
    class Animal:
        able="Run"
        def __init__(self,name):
            self.name=name
        def eat(self):
            print('%s会吃' %(self.name))
        def bark(self):
            print('%s会叫' %self.name)
    a1=Animal("Dog")
    print(a1.name)
    print(a1.__dict__["name"])
    # a1.name 等价于 a1.__dict__["name"]
    # 1 hasattr(object,name) 判断object中有没有一个name字符串对应的方法或属性
    print(hasattr(a1,'able')) #True
    print(hasattr(a1,'eat')) #True
    print(a1.__dict__)  #{'name': 'Dog'}
    # 虽然__dict__中没有eat方法,但是,这里只是检查能否调用到
    # 2 getattr(object,name) 等价于 a1.属性或方法  获取对应的方法或属性
    print(getattr(a1,'able')) #Run
    print(getattr(a1,'eat')) #<bound method Animal.eat of <__main__.Animal object at 0x0000000002564630>>
    # 如果没有就报错,通过默认参数的方法可以不报错
    print(getattr(a1,'11111',"该属性不存在"))
    print(getattr(a1,'2222',"该方法不存在"))
    # 3 getattr(object,k,v) 等价于 a1.属性或方法=''  判断设置对应的方法或属性
    setattr(a1,'able2','run')  #创建
    setattr(a1,'able','drink') #修改
    print(getattr(a1,'able')) #drink
    print(getattr(a1,'able2')) #run
    # 4 delattr(object,k,v) 删除对应的方法或属性
    delattr(a1,'able')
    View Code
    # 反射:自省,自己检测自己。主要指程序可以访问、检测和修改它本身状态或行为的一种能力
    class Animal:
        able="Run"
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def eat(self):
            print('%s会吃' %(self.name))
        def bark(self):
            print('%s会叫' %self.name)
    
        def __getattr__(self, item):
            print("调用__getattr__(self, item)方法")
        # __setattr__()方法不常用,但可以通过重写该方法,实现自己特殊的需求,如类型只能是字符串
        def __setattr__(self, key, value):
            if key.strip()=="name":
                if type(value) is str:
                    self.__dict__[key] = value
                else:
                    print("name必须是字符串")
            else:
                self.__dict__[key] = value
        def __delattr__(self,item):
            self.__dict__.pop(item)
    a1=Animal("Dog",12)
    # __开头表示内置属性
    # 修改属性
    a1.__setattr__('name',15)
    print(a1.__dict__) #{'name': 'Dog', 'age': 12}
    del a1.name #调用__delattr__(self, item)方法
    # 只有在属性不存在的时候会触发__getattr__
    print(a1.abccccc)
    反射2
    # 导入其他模块进行反射
    import pkage1.say as p
    
    print(hasattr(p,"sayHello"))
    print(getattr(p,"sayHello111","不存在"))
    导入其他模块进行反射
    # 反射可以使代码更灵活,易于扩展
    # Why?因为反射可以根据字符串去获取、访问变量
    
    class Manager:
        # 定义成操作列表,列表的优势是可以通过下标索引来访问
        OPERATE_DIC = [
            ('创建班级', 'create_class'),
            ('创建课程', 'create_course'),
            ('创建学生', 'create_student'),
        ]
    
        def __init__(self, name):
            self.name = name
    
        def create_class(self):
            print("创建班级")
    
        def create_course(self):
            print("创建课程")
    
        def create_student(self):
            print("创建学生")
    
    
    class Student:
        OPERATE_DIC = [
            ('选择班级', 'choose_class'),
            ('选择课程', 'choose_course'),
        ]
    
        def __init__(self, name):
            self.name = name
    
        def choose_class(self):
            print("选择班级")
    
        def choose_course(self):
            print("选择课程")
    
    
    def login():
        userName = input("账号:")
        pwd = input("密码:")
        with open("用户表") as f:
            for line in f:
                user, password, role = line.strip().split("|")
                if user == userName and password == pwd:
                    return user, role
            else:
                print("用户不存在")
    
    
    def main():
        user, role = login()
        if user and role:
            print("欢迎%s:%s" % (role, user))
            # 根据用户角色反射出用户类--开始
            # 1:自己文件反射需要引入包
            import sys
            # 2:根据字符串去获取文件中的类(灵活的判断是Manager还是Student)
            cls = getattr(sys.modules["__main__"], role)
            # 3:根据类创建对象
            obj = cls(user)
            op_dic = obj.OPERATE_DIC
            # 4: 有了对象,调用发方法
            while True:
                #enumerate方法是将op_dic 组合为一个索引序列,同时列出数据和数据下标
                for num,i in enumerate(op_dic,1):
                    print(num,i)
                chooseNum= int(input("请输入操作序号:"))
                # 根据用户输入的操作序号,获取相应的操作方法名,字符串
                op_fun = op_dic[chooseNum-1][1]
                #通过对象的反射,对象.方法名 ;调用
                getattr(obj,op_fun)()
    main()
    反射典型--登录系统
    # 反射场景:
    # 表:网关、夜灯、呼叫器、上下线记录表
    # 关系:一个网关下有多个夜灯、呼叫器,子表中通过(网关的id)关联网关表,
    #       所有的设备(网关、夜灯、呼叫器)的上下线记录都会存储在上下线记录表中(设备id,设备类型)
    #  我们根据记录表中的设备id要反向关联出是设备的详细信息,如何处理。
      from deviceApp import models as TModel
    # 首先定义一个枚举类型(light【设备类型,网关表中存储的数据】,"NightLightDevice" Model类中的名字)
    # @unique
    # class DeviceType(Enum):
    #     # 定义设备类型,根据设备类型对应不同
    #     light = "NightLightDevice"
    #     gate = "GatewayDevice"
    #     call = "CallbuttonDevice"
        
        
        
    #     deviceType = request['deviceType']  # 设备产品  例如call
    # # 1. 根据deviceType关联枚举类型,利用反射获取相应的model类
    #    cls = getattr(TModel, DeviceType[deviceType].value, None)
    #    if cls:
    #        # 如果model类存在,根据主键id,找到对应的设备实体
    #        child_device_obj = cls.objects.get(id=deviceId)
    #    else:
    #        return failResultJson(msg='getattr-TModel对象失败')
    反射应用场景

    8 二次加工标准类型

    # 方法1,通过继承实现
    class ListYK(list):
        # 添加一个新方法,求取中间值
        def show_middle(self):
            mid_index=int(len(self)/2)
            return self[mid_index]
    
        # 重写一个添加方法,只能添加字符串
        def append(self,p_object):
            if type(p_object) is str:
                # list.append(self,p_object)
                super().append(p_object)
    l1=ListYK("hello")
    print(l1.show_middle()) #l
    l1.append("1")
    l1.append(2)
    print(l1) #['h', 'e', 'l', 'l', 'o', '1']
    
    # 2授权:授权时包装的一个特性,包装一个类型通常是对已存在的类型的一些定制
    # 授权的过程,及时所有更新的功能都是有新类的某部分来处理,但已存在的功能就授权给队形的默认属性
    import time
    class OpenNew:
        def __init__(self,filename,mode='r',encoding="utf-8"):
            self.file=open(filename,mode,encoding=encoding)
            self.filename=filename
            self.mode = mode
            self.encoding = encoding
        def __getattr__(self, item):
            return getattr(self.file,item)
        def write(self,line):
            t = time.strftime('%Y-%m-%d %T')
            self.file.write('%s %s' % (t, line))
    f1=OpenNew("a.txt","w+","utf-8")
    f1.write("111
    ")
    f1.write("222")
    View Code

    9 __new__

     1 class Single:
     2      def __new__(cls, *args, **kwargs):
     3          obj = object.__new__(cls)     #类名() 调用了new方法,开辟可一个空间给obj。
     4          print("init中的self:", obj)
     5          return obj
     6      def __init__(self):
     7          print("init中的self:",self)
     8 sin=Single()
     9 
    10 # 输出结果,
    11 # init中的self: <__main__.Single object at 0x00CDA930>
    12 # init中的self: <__main__.Single object at 0x00CDA930>
    13 
    14 # 结论:line 8 :类名() 调用了new方法,开辟可一个空间给obj。
    15 #       然后把obj的空间给self。#       
    16 #       line 6 :执行__init__ 方法
    17 #       最后把空间给调用者sin
    __new__
    class Single:
        ISINCTANCE=None
        def __new__(cls, *args, **kwargs):
            if not cls.ISINCTANCE:
                cls.ISINCTANCE = object.__new__(cls)
            return cls.ISINCTANCE
    
        def __init__(self, *args, **kwargs):
            pass
    
    
    a = Single()
    print(a)
    b = Single()
    print(b)
    
    ''' 输出结果
    <__main__.Single object at 0x00F5FE70>
    <__main__.Single object at 0x00F5FE70>
    '''
    # 结论,先定义属性,new的时候判断该属性是否有值,如果有值返回。没有值再new值
    单例

    10 __getattribute__与__getattr__

    #__getattribute__与__getattr__
    
    # 1:只有__getattr__存在的情况下,只有获取的属性不存在,才触发此方法
    
    class Foo:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def getInfo(self):
            return "My name is %s,I am %s years old" % (self.name, self.age)
        def __getattr__(self,item):
            print("我是__getattr")
    
    f = Foo("Mr.zhang", 18)
    f.name
    f.agea  #只有属性不存在的时候,才会触发
    
    class Foo2:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def getInfo(self):
            return "My name is %s,I am %s years old" % (self.name, self.age)
        def __getattribute__(self, item):
            print("我是__getattribute__")
    
    f2 = Foo2("Mr.zhang", 18)
    f2.name
    f2.agea
    #不管是否存在,都会触发__getattribute__方法
    class Foo3:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def getInfo(self):
            return "My name is %s,I am %s years old" % (self.name, self.age)
    
        def __getattribute__(self, item):
            print("我是__getattribute__")
            raise AttributeError("属性不存在,就会触发getattr方法")
        def __getattr__(self, item):
            print("我是__getattr")
    print("F3=======>")
    f3 = Foo3("Mr.zhang", 18)
    f3.name
    f3.agea
    # 不管是否存在,都会触发__getattribute__方法,当都_getattribute__方法抛出AttributeError异常时,触发__getattr__方法
    #__getattribute__与__getattr__

    11 __item__

    class Foo:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def getInfo(self):
            return "My name is %s,I am %s years old" % (self.name, self.age)
        def __getitem__(self, item):
            print("我是__getitem__方法")
            return self.__dict__[item]
        def __setitem__(self, key, value):
             self.__dict__[key]=value
        def __delitem__(self, key):
            self.__dict__.pop(self.__dict__[key])
    
    
    f = Foo("Mr.zhang", 18)
    print(f["name"])
    f["age"]="12"
    print(f["age"])
    del  f.age
    print(f.__dict__)
    '''
    我是__getitem__方法
    Mr.zhang
    我是__getitem__方法
    12
    {'name': 'Mr.zhang'}
    '''
    View Code

    12 __str__与__repr__

    # 注意:这两个方法的返回值必须是字符串
    # 如果__str__没有定义,那么就会__repr__替代
    class Foo:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def __str__(self):
            return ("我叫%s 今年%s岁了" %(self.name,self.age))
    
        def __repr__(self):
            return ("我今年%s岁了 叫%s " % (self.age,self.name))
    
    f=Foo("杨可",26)
    print(f)
    #str函数或者print函数 --》obj.__str__()
    #repr或者交互式解释器--》obj.__repr__()
    #如果__str__没有被定义,那么就会使用__repr__来代替
    __str__ __repr__

    13 __len__

    class Student:
        def __len__(self):
            return len(self.name)
        def __init__(self,name):
            self.name=name
    
    st=Student("张三")
    print(len(st))
    st=Student("尼古拉斯赵四儿")
    print(len(st))
    __len__

    14 __hash__

    class Employee:
        def __init__(self, name, sex, age, dept):
            self.name = name
            self.sex = sex
            self.age = age
            self.dept = dept
    
        def __hash__(self):
            return hash('%s%s' % (self.name, self.sex))
    
        def __eq__(self, other):
            if self.name == other.name and self.sex == other.sex:
                return True
    
    
    employ_lst = []
    for i in range(1000):
        if i % 3 == 0:
            employ_lst.append(Employee('张三', 'male', i, 'python'))
        elif i % 3 == 1:
            employ_lst.append(Employee('李四', 'male', i, 'python'))
        else:
            employ_lst.append(Employee('王五', 'male', i, 'python'))
    employ_newList = set(employ_lst)
    for i in employ_newList:
        print(i.name, i.sex, i.age)
    '''
    1:定义一个员工类(Employee)
    2:对象的属性 : 姓名 性别 年龄 部门
    3:重写__hash__方法
    4:重写__eq__方法
    5:初始化数据
    6:set去重
    '''
    
    '''输出结果
    李四 male 1
    张三 male 0
    王五 male 2
    '''
    员工去重

    15 查看实例的来源

    from pkage1.Foo import Foo
    
    f = Foo()
    print(f.__module__)
    print(f.__class__)
    # pkage1.Foo
    # <class 'pkage1.Foo.Foo'>
    View Code

    16 析构函数

    class Foo:
        def __init__(self,name):
            self.name=name
        def __del__(self):
            print("析构函数")
    f = Foo("zhangsan")
    del f
    View Code

    17 __call__    利用 ()可以执行

    class Foo:
        def __call__(self, *args, **kwargs):
            print("实例执行了call方法")
    f=Foo()
    f()
    # 实例执行了call方法
    call方法
    class Foo:
        def __call__(self, *args, **kwargs):
            print("实例执行了call方法")
    
    
    class Foooo:
        def __init__(self,cls):
            self.c=cls()  #实例化传递过来的cls,也就是Foo
            self.c()    # ()调用Foo中的__call__ 方法
    
    Foooo(Foo)
    在源码中比较常用的()

    18 迭代器协议

    # 迭代器协议:有一个iter方法,有一个next方法,有Stopiteration终止
    class Foo:
    
        def __init__(self,x,prv=0,cur=1):
            self.x=x
            self.prv = prv
            self.cur = cur
        def __iter__(self):
            return self
        def __next__(self):
            if self.x>100:
                raise StopIteration("越界了")
            self.x =  self.prv + self.cur
            self.prv =self.cur
            self.cur= self.x
            return self.cur
    f =Foo(10)
    print(f.__next__())
    print(next(f))
    
    print("====>")
    for i in f:
        print(i)
    
    # 1
    # 2
    # ====>
    # 3
    # 5
    # 8
    # 13
    # 21
    # 34
    # 55
    # 89
    # 144
    斐波那契数列

     19 上下文管理协议

    # 上下文管理协议
    # with obj as  f 等同于 f=obj.__enter__()
    # 执行代码块
    # 一:没有异常,整个代码块运行完毕后触发__exit__,它的三个参数都为None
    # 二:出现异常,直接触发__exit__
    #     a:如果__exit__的返回值为True,代表吞掉了异常
    #     b:如果__exit__的返回值不为True,代表吐出来异常
    #     c:__exit__的运行完毕,代表整个with语句执行完毕
    class OpenNew:
        def __init__(self,name):
            self.name = name
        def __enter__(self):
            print('执行enter')
        def __exit__(self, exc_type, exc_val, exc_tb):
            print("执行exit方法")
            print("3")
            print(aa)
            print(exc_type)
            print(exc_val)
            print(exc_tb)
            print("4")
            return True
    with OpenNew("a.txt") as  f:
        print('1')
        print('2')
    print('5')
    View Code

    20 描述符

    #描述符协议:描述符本质就是一个新式类,至少实现了__get__(),__set__(),__delete__()中的至少一个
    # __get__(),调用属性时触发
    # __set__(),为属性赋值是触发
    # __delete__(),删除属性时触发
    # 描述符作用:可以用来定义一个类的属性,
    # 描述符的特性:由该类产生的实例变化时候不会调用这些个方法,定义另外一个属性时,会被调用
    # 描述符分类:没有实现__set__()的叫非数据描述符,实现了__set__()和__get__()的叫数据描述符
    # 注意事项:1:描述符本身和被代理类都是新式类,2:定义成类的属性,,不能定义到构造函数中
    #定义一个描述符
    class StrNew:
        def __get__(self, instance, owner):
            print("Str调用__get__")
        def __set__(self, instance, value):
            print("Str调用__set__")
        def __delete__(self, instance):
            print("Str调用__delete__")
    class IntNew:
        def __get__(self, instance, owner):
            print("Int调用__get__")
        def __set__(self, instance, value):
            print("Int调用__set__")
        def __delete__(self, instance):
            print("Int调用__delete__")
    class People:
        name=StrNew()
        age=IntNew()
        def __init__(self,name,age):
            self.name=name
            self.age=age
    p=People('张三',15)
    p.name
    p.name="张三New"
    del  p.name
    p.age
    p.age=15
    del p.age
    
    # 优先级
    # 1:类属性>2:数据描述符>3:实例属性>4:非数据描述符>5:找不到属性触发__getattr__()
    # print("1:类属性>2:数据描述符")
    # People.name #调用类属性name 本质是调用描述符__get__()方法
    # People.name="zhangsan" #它拥有更高的优先级,相当于覆盖了描述符,肯定不会触发描述符的
    # del People.name
    
    print("2:数据描述符>3:实例属性")
    p=People('张三',15)
    p.name="lisi"
    print(p.__dict__)  #{}
    # 与实例相关的属性字典中没有name,因为name是一个数据描述符,优先级高于实例属性,操作都是跟描述符有关,与实例无关了
    描述符协议
    # python 是弱类型,可以通过描述将其设置为强类型
    # 定义一个类型控制的描述符
    class TypeControl:
        # 定义一个构造函数,用于初始化,字段名称(根据名称对其进行设置)和类型(设置值是做判断)
        def __init__(self,name,typeName):
            self.name=name
            self.typeName = typeName
        def __get__(self, instance, owner):
            print("调用__get__")
            return instance.__dict__[self.name]
        def __set__(self, instance, value):
            print("调用__set__")
            # //如果设置值的属性和定义的属性不一致,报错
            if not isinstance(value,self.typeName):
                raise TypeError
            instance.__dict__[self.name]=value
        def __delete__(self, instance):
            print("调用__delete__")
            instance.__dict__.pop(self.name)
    
    class People:
        name=TypeControl("name",str)
        age=TypeControl("age",int)
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
    p=People('张三',15)
    p.name
    del p.name
    
    p=People('1',1)
    p.name
    del p.name
    定义一个类型控制的描述符

    21 装饰器

    # 装饰器=高阶函数+函数嵌套+闭包
    # 高阶函数:传入参数或输出结果是一个函数
    # 函数嵌套:函数中定义函数
    import time
    # 添加一个参数,如果参数是n就打n折
    def disCount(n=1):
        def timmer(func):
            def wrapper(*args,**kwargs):
                startTime= time.time()
                res=func(*args,**kwargs)*n;
                endTime= time.time()
                print("今天是国庆节,每位客户打的折扣为:"+str(n*10))
                return  res
            return wrapper
        return timmer
    #@timmer  #语法糖,相当于#test=timmer(test)
    @disCount(n=0.9)
    def test(a,b):
        return a+b
    
    print(test(100,200))
    装饰器
    # 定义一个用户列表
    userList=[{"name":"zhangsan","pwd":"333"},{"name":"lisi","pwd":"444"},{"name":"wangwu","pwd":"555"}]
    currentUser={"name":"None","loginState":"False"}
    def SignOut():
        currentUser = {"name": "None", "loginState": "False"}
    
    def authority(func):
        def wapper(*args,**kwargs):
            if currentUser["name"] and eval(currentUser["loginState"]):
                res = func(*args,**kwargs)
                return res
            else:
                SignIn();
        return wapper
    def index():
        print("欢迎来到登录页面")
    @authority
    def home():
        print("欢迎回家%s" %currentUser["name"])
    @authority
    def shopping_car():
        print("%s的购物车中有:苹果、葡萄。" %currentUser["name"])
    
    def SignIn():
        print("请先登录")
        userName = input('用户名:').strip()
        userPwd = input('密码:').strip()
        for userInfo in userList:
            if userInfo["name"] == userName and userInfo["pwd"] == userPwd:
                currentUser["name"] = userName
                currentUser["loginState"] = "True"
        if currentUser["name"] and eval(currentUser["loginState"]):
            print("登录成功,")
        else:
            print("用户名或密码错误")
            SignIn()
    index()
    home()
    shopping_car()
    装饰器,修饰方法
    class TypeControl:
        # 定义一个构造函数,用于初始化,字段名称(根据名称对其进行设置)和类型(设置值是做判断)
        def __init__(self,name,typeName):
            self.name=name
            self.typeName = typeName
        def __get__(self, instance, owner):
            print("调用__get__")
            return instance.__dict__[self.name]
        def __set__(self, instance, value):
            print("调用__set__")
            # //如果设置值的属性和定义的属性不一致,报错
            if not isinstance(value,self.typeName):
                raise TypeError
            instance.__dict__[self.name]=value
        def __delete__(self, instance):
            print("调用__delete__")
            instance.__dict__.pop(self.name)
    
    def typeAssert(**kwargs):
        def decorateClass(cls):
            for name,expected_type in kwargs.items():
                setattr(cls,name,TypeControl(name,expected_type)) #People.name = TypeControl('name',str)
            return cls
        return decorateClass
    
    #传递字典参数,运行typeAssert(),返回decorateClass
    # 继续执行@decorateClass
    # 执行@decorateClass给类添加属性
    @typeAssert(name=str,age=int)
    class People:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
    p=People('张三',15)
    p.name
    del p.name
    装饰器,修饰类

    22 自定义Property属性

    class myProperty:
        def __init__(self,func):
            self.func=func
        def __get__(self, instance, owner):
            # 描述符中调用func函数
            # 直接用类调用会由于instance是None,导致运行func()报错
            if instance is None:
                return self
            return self.func(instance)
    class Room:
        def __init__(self,name,length,width):
            self.name=name
            self.length=length
            self.width = width
        @myProperty #getArea=myProperty(getArea)
        def getArea(self):
            return self.width*self.length
    r1=Room("卧室",6,4)
    print(r1.getArea)
    print(Room.getArea)
    # 思路@myProperty相当于getArea=myProperty(getArea)
    #1:定义一个getArea=myProperty(getArea)
    #2:其中定义一个构造函数,接收传递过来的函数名并返回,相当于类的装饰器功能
    #3:要想通过.方法名掉用方法。需要通过描述符(3:实例属性>4:非数据描述符)
    自定义属性myProperty
    class myProperty:
        def __init__(self,func):
            self.func=func
        def __get__(self, instance, owner):
            print("get")
            # 描述符中调用func函数
            # 直接用类调用会由于instance是None,导致运行func()报错
            if instance is None:
                return self
            res = self.func(instance)
            setattr(instance,self.func.__name__,res)
            return res
    class Room:
        def __init__(self,name,length,width):
            self.name=name
            self.length=length
            self.width = width
        @myProperty #getArea=myProperty(getArea)
        def getArea(self):
            return self.width*self.length
    r1=Room("卧室",6,4)
    print(r1.getArea)
    print(Room.getArea)
    print("=======>懒加载,只调用一次,原理:把getArea添加到r1的数据字典中,然后直接从字典中获取")
    print(r1.getArea)
    print(r1.getArea)
    print(r1.getArea)
    
    # 思路@myProperty相当于getArea=myProperty(getArea)
    #1:定义一个getArea=myProperty(getArea)
    #2:其中定义一个构造函数,接收传递过来的函数名并返回,相当于类的装饰器功能
    #3:要想通过.方法名掉用方法。需要通过描述符(3:实例属性>4:非数据描述符)
    懒加载myProperty

     23 元类

    # 我们用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类(元类可以简称为类的类),内置的元类为type
    # print(type(Foo)) # 结果为<class 'type'>,证明是调用了type这个元类而产生的Foo,即默认的元类为type
    #
    # class关键字在帮我们创建类时,必然帮我们调用了元类OldboyTeacher=type(...),那调用type时传入的参数是什么呢?必然是类的关键组成部分,一个类有三大组成部分,分别是
    # 1、类名class_name='Foo'
    # 2、基类们class_bases=(object,)
    # 3、类的名称空间class_dic,类的名称空间是执行类体代码而得到的
    # 调用type时会依次传入以上三个参数
    class MyType(type):
        def __init__(self):
            print("")
        def __call__(self, *args, **kwargs):
            # 此时self 是Foo,
            #object.__new__(self) 相当于以Foo为类创建对象,即:产生f1
            obj=object.__new__(self)
            #调用Foo下面的init方法
            self.__init__(self,*args, **kwargs)
    class Foo(metaclass=MyType):
        def __init__(self,name):
            self.name=name
    View Code

     24 总结

    • 面向对象的过程
      • 1 开辟一个空间__new__(),属于对象的
      • 2 把对象的空间传递给self,执行__init__()方法
      • 3 把对象空间返还给调用者
    • 内置方法、双下方法、魔术方法 
      • 1 格式:__方法名__
      • 内置函数和类的内置方法之间联系紧密
      • 常见的内置方法有 __new__ __init__ __call__ __str__...
    • set去重原理
      • set() 函数中会先调用对象的 __hash__() 方法,获取 hash 结果;
      • 如果 hash 结果相同,用比较操作符 == (也就是调用函数 __eq__())判断二者的值是否相等;
      • 如果都相等,去重;否则,set() 认为二者不同,两个都保留到结果中。
  • 相关阅读:
    SCOI2020游记
    关于我
    WC2020游记
    CSP-S 2019 游记
    回文自动机学习笔记
    全自动数字论证机(迫真)
    树状数组上二分
    《伊豆的舞女》 读书小记
    雅礼集训2019 Day5
    雅礼集训2019 Day4
  • 原文地址:https://www.cnblogs.com/YK2012/p/9748654.html
Copyright © 2020-2023  润新知