zoukankan      html  css  js  c++  java
  • 饮冰三年-人工智能-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() 认为二者不同,两个都保留到结果中。
  • 相关阅读:
    Delphi XE4 FireMonkey 开发 IOS APP 发布到 AppStore 最后一步.
    Native iOS Control Delphi XE4
    Delphi XE4 iAD Framework 支持.
    using IOS API with Delphi XE4
    GoF23种设计模式之行为型模式之命令模式
    Android青翼蝠王之ContentProvider
    Android白眉鹰王之BroadcastReceiver
    Android倚天剑之Notification之亮剑IOS
    Android紫衫龙王之Activity
    GoF23种设计模式之行为型模式之访问者模式
  • 原文地址:https://www.cnblogs.com/YK2012/p/9748654.html
Copyright © 2011-2022 走看看