python基础13-item/__str__方法/__format__方法/__slots__方法/_cal_方法/迭代器协议/描述符

  • 文件也是对象,也可以用反射模块中的四个方法
  • 在团队协作中,可插拔机制,使用反射方法判断下模块中是否有对应的函数
  • 导入就是将文件拿过来,在当前文件中执行一遍
  • #导入其他模块用import as的方法,想在模块自身应用反射方法,需要通过以下语句方法来导入模块本身,然后应用反射的方法
    import
    sys obj1=sys.modules[__name__]#__name__是当前模块名,
    sys.modules通过key的方法能取到当前模块
    print('==>',hasattr(obj1,'x')) 
  • 内置函数补充

  • isinstance(obj,cls)判断一个对象obj是否为某类class本身或子类生成的实例
  • issubclass(sub,super)判断sub是否为super的子类
  • type(b1)显示实例b1所属的类
  • !没啥用__getattribute__:属性存在,返回匹配的值。属性不存在,抛出一个异常
  • class Foo:
        def __init__(self,x):
            self.x=x
    
        def __getattr__(self, item):
            print('执行的是getattr')
    
        def __getattribute__(self, item):#甭管属性是否能找到,都会触发此,
            print('执行的是getattribute')
            raise AttributeError('抛出异常了')#在此抛出这个指令的情况下,才会触发getattr
    
    f1=Foo(10)
    # f1.x
    f1.xxxxx

     

  • item系列

  • #.的调用方式跟getattr等三个方法相关,字典形式的操作跟getitem等三个方法相关
    class
    Foo: def __getitem__(self, item): print('getitem') return self.__dict__[item] def __setitem__(self, key, value): print('setitem') self.__dict__[key] = value # 模拟字典新增键值对的方法 def __delitem__(self, key): print('delitem') self.__dict__.pop(key) f1 = Foo() print(f1.__dict__) # f1.name='egon'#这种方式不会触发setitem f1['name'] = 'egon' # 按照字典方式赋值,会触发setitem方法,字典是['属性']的形式 f1['age'] = 18 print(f1.__dict__) del f1.name # 通过.的方式,跟delattr那种方式匹配,不匹配delitem的方式 print(f1.__dict__)
  • str方法:改变对象的字符串显示

  • 一切皆对象,打印时本质都应该是object,有些对象的打印结果不是object。表明可以在自己的类中定制一些方法,来控制该类实例出的对象输出结果是什么形式
  • class Foo:
        #类中有默认的str方法,如果不自定义,则采用系统的
        def __str__(self):#自定义该类实例的对象的打印结果
            return '自定制的对象的显示方式'#必须return字符串类型
    f1=Foo()
    print(f1)#本质是就调用的--str(f1)--方法,就是f1.__str__()方法

     

  • #在解释器中用__repr__
    class
    Foo: #类中有默认的str方法,如果不自定义,则采用系统的 def __str__(self): return '这是str' def __repr__(self):#自定义该类实例的对象的打印结果 return '名字是%s 年龄是%s'%(self.name,self.age)
    #不能return非字符串格式 f1
    =Foo() #在解释器中输入f1#本质是就调用的--repr(f1)--方法,就是f1.__repr__()方法 print(f1)#如果有str就找str,如无,则找repr。如都无,则找系统内置的

     

  • 为实例定制format

  • format_dic = {
        'ymd': '{0.year}{0.mon}{0.day}',
        'm-d-y': '{0.mon}-{0.day}-{0.year}',
        'y:m:d': '{0.year}:{0.mon}:{0.day}'
    }
    
    
    class Date:
        def __init__(self, year, mon, day):
            self.year = year
            self.mon = mon
            self.day = day
    
        def __format__(self, format_spec):
            print('我执行啦')
            print('-->', format_spec)
            if not format_spec or format_spec not in format_dic:
                format_spec = 'ymd'
            fm = format_dic[format_spec]
            return fm.format(self)
    
    
    d1 = Date(2016, 12, 26)
    # format(d1)
    print(format(d1, 'y:m:d')) 
  • slots属性

  • _solts_是一个类变量,变量值可以是列表,元组或者可迭代对象,也可以是字符串(意味着所有实例只有一个数据属性)
  • 类的字典是共享的,供该类产生的实例调用
  • 当类的属性很少,但是需要产生成千上万的实例时,每个实例都有独立的存储空间,很浪费内存
  • _slots_上场后,每个实例不再有_dict_,这样不用为每个实例创建属性字典,节省内存空间
  • class Foo:
        # __slots__ = ['name','age']
        __slots__ = 'name'  # 不用每个实例创建属性字典,统一到类属性字典中找
        # 缺点:每个实例只能创建一个name的属性,不能创建其他属性
        # 优势所在是省内存,而不是处于限制实例扩展属性
    
    
    f1 = Foo()
    f1.name = 'egon'
    print(f1.name)
    
    # print(f1.__dict__)
    print(f1.__slots__)

     

  • _doc_类方法

  • class Foo:
        '我是描述信息'  # 这个信息不能被继承
        pass
    class Bar(Foo):
        pass
    print(Bar.__doc__)
  • c1.__module__获取当前c1是哪个模块产生的
  • c1.__class__查看c1是哪个模块的哪个类产生的
  • __del__函数又叫析构函数

  • 与描述符__delete__不同,当对象在内存中释放时,自动触发执行,一般无需定义。只在实例被删除,或者程序执行完毕后运行
  • __call__方法

  • 对象后边加括号,触发执行,呼叫不动。f1(),就是实例f1调用创建该实例的类的call方法
    class Foo:
        def __call__(self, *args, **kwargs):
            print('实例执行了,obj()')
    
    
    f1 = Foo()
    f1()  # 执行就是调用该实例的类的call方法
    Foo()  # 调用创建该Foo实例的类的call方法#类是对象,所以也是别的类产生的

 

  •  迭代器协议

  • for循环的步骤,先通过_iter_方法把对象变为可迭代对象
  • #手动实现迭代器协议,包括iter和next方法即可
    class Foo: def __init__(self, n): self.n = n def __iter__(self): return self def __next__(self): if self.n==100: raise StopIteration('终止了') self.n += 1 return self.n f1 = Foo(10) print(f1.__next__()) print(f1.__next__()) print(f1.__next__()) print(next(f1)) for i in f1:#步骤一,iter(obj),步骤二,调用obj.__iter__方法,步骤三,调用迭代器的__next__方法 print(i)

     

  • # 迭代器实现斐波那契数列
    class Fib:
        def __init__(self):
            self._a = 1
            self._b = 1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self._b > 100:
                raise StopIteration('终止了')
            self._a, self._b = self._b, self._a + self._b
            return self._a
    
    
    f1 = Fib()
    print(next(f1))
    print(next(f1))
    print(next(f1))
    print('>>>>>>>>>>>>>>')
    for i in f1:#接着上边的for循环开始
        print(i)
  • 描述符

  • 如果一个类中包含三个魔术方法(__get__)(__set__)(__delete__)方法,该类就称为一个描述符
  • 描述符的作用,就是对类或对象中某个成员进行详细的管理操作。描述符只管理某个成员,而setattr则是管理全部数据
  • 数据描述符就至少有get和set,非数据描述符没有set
  • 要想使用描述符,必须在类之前声明描述符
  • 属性描述方法和描述符的区别
  1. 属性描述方法,__getattr__, __setattr__, __delattr__等。针对当前类/对象的所有成员的管理,属性描述方法仅对当前类有效
  2. 描述符,__del__,  __set__,  __deleate__。仅仅针对类/对象某一个成员的设置,描述符可对不同的类使用
  • 描述符的使用方法
  1. 在py文件中定义一个描述符,既描述符,包括以上三个魔术方法
  2. 然后在想调用的类中,讲数据属性或函数属性=描述符,即交给描述符管理,
  3. 最后,在描述的三个魔术方法中,设置对应的返回值,或者设置,删除等操作即可
  • 属性描述方法的使用方法
  1. 定义在类中,在满足条件时,触发类中自定义的getattr方法
  2. 如果没有定义,则调用系统内置的getattr方法
  • 描述符第二种使用方式,将描述符和应用类写在一个类中,然后将成员交给描述符管理,username=property(获取描述符getusername,设置描述符 setusername, 删除描述符delusername, 文件d=‘  ’)
  • #描述符的第三种使用方式
    @property # 将用户名交给描述符管理,默认是get描述符 def username(self): pass @username.setter # 设置描述符 def username(self,val): pass @username.deleter # 删除描述符 def username(self): pass
  • 描述符的优先级。类属性>数据描述符>实例属性>非数据描述符>找不到的属性触发getattr
  • 软件开发规范

  1. 有bin目录,放置可执行文件。写一端小的脚本,不同角色登录程序
  2. 有conf文件。静态配置
  3. db存放数据
  4. lib,公共类库,公共功能
  5. log模块
  6. src,core存储核心逻辑
  • 对象序列化后,在打开时,对象是依托类存在的,要在打开序列文件的程序导入类方可执行
  • python干的好事

  • 新建包或者目录后,pycharm会自动将当前路径加入环境变量中
  • 为了让程序在所有平台都能用,执行以下步骤
  • import sys, os
    
    BASE_DIR = os.path.dirname(os.path.dirname(__file__))
    sys.path.append(BASE_DIR)

     

posted @ 2022-01-18 12:00  线索  阅读(34)  评论(0编辑  收藏  举报