zoukankan      html  css  js  c++  java
  • Python魔法方法之容器部方法(__len__,__getitem__,__setitem__,__delitem__,__missing__)(更新版本)

    为了加深印象,也为了以后能够更好的回忆,还是记录一下。

    序列(类似集合,列表,字符串),映射(类似字典)基本上是元素的集合,要实现他们的基本行为(协议),不可变对象需要两个协议,可变对象需要4个协议。

    __len__(self):返回元素的数量,(为不可变对象需要的协议之一)=====> len

    __iter__返回一个迭代器,具有了__next__方法后,给for使用。

    __contains__ 代表 in的意思 xx.__contains__ (22) ==>22 in xx一个效果

    __getitem__(self, key)或者__getitem__(self, index), 返回执行输入所关联的值(为不可变对象需要的协议之一)

    __setitem__(self, key, values) 或者 __setitem__(self, index, values) , 设置指定输入的值对应的values

    __delitem__ (self, key) 删除指定key的值

    __missing__这个有意思,跟__getattr__有的一比,是找不到这个key,触发条件。前面用列表测试了,晕死了(只对字典有效。)

    __del__, 析构函数当这个类不存在实例对象时执行。

    下面我编写一个自定义类似列表的类,实例后该类默认前面有10个None参数,且不能删除前面5个空None。(随口说的,开始写了)

    def check_index(index):
        if index < 5:
            raise IndexError('index must greater than 10')
    
    
    class S_List:
        def __init__(self):
            self.ll = [None] * 10
    
        def __len__(self):  # 提取参数长度
            return len(self.ll)
    
        def __getitem__(self, index):  # 取出参数
            return self.ll[index]
    
        def __setitem__(self, index, value):  # 设置参数
            check_index(index)
            self.ll[index] = value
    
        def __delitem__(self, index):
            check_index(index)
            self.ll.pop(index)
    
        def __str__(self):  # 打印对象时,输出列表本身
            return str(self.ll)
    
        def __del__(self):  # 没有手工删除在程序结束时释放
            print('我被释放了!')
    
    
    sl = S_List()
    del sl[3]
    
    print(isinstance(sl, S_List))
    print(f'输出原始数据:{sl}')
    sl[6] = 'six'
    print(f'修改后原始数据:{sl}')
    print(f'随便取一个值:{sl[1]}')
    del sl[6]
    print(f'第二次修改后原始数据:{sl}')
    del sl[3]
    # sl[4] = 'oh'
    print(sl)
    

     正常输出:

    True
    输出原始数据:[None, None, None, None, None, None, None, None, None, None]
    修改后原始数据:[None, None, None, None, None, None, 'six', None, None, None]
    随便取一个值:None
    第二次修改后原始数据:[None, None, None, None, None, None, None, None, None]
    [None, None, None, None, None, None, None, None, None]
    我被释放了!
    

     报错提示:

    Traceback (most recent call last):
      File "/Users/shijianzhong/Desktop/yunzuan_buy/study_base.py", line 81, in <module>
        del sl[3]
      File "/Users/shijianzhong/Desktop/yunzuan_buy/study_base.py", line 73, in __delitem__
        check_index(index)
      File "/Users/shijianzhong/Desktop/yunzuan_buy/study_base.py", line 53, in check_index
        raise IndexError('index must greater than 10')
    IndexError: index must greater than 10
    我被释放了!
    

    这个是自定义的一个基本没有什么方法的伪字典,不能增加元素,而且index,count等方法由于没有写入都无法使用。

    好的方式是可以继承list或者dict的类,在里面对需要的条件进行修改限制,这样的话,实例出来的对象可以继承原来的全部方法。

    插入一个直接不用初始化自定义变量,直接借用__dict__来实现伪字典型的取值复制。

    class Ii:
        def __getitem__(self, item):
            return self.__dict__[item]
        def __setitem__(self, key, value):
            self.__dict__[key] = value
    
    li = Ii()
    li[3] = 5
    print(li[3])
    
    # 5
    

    这次我可以正真的定义个超级列表,根据我的需要。现在要求这个列表初始化有5个None元素,前面5个元素不能修改,后面添加的元素必须为str

    def check_str(params):
        if not isinstance(params, str):
            raise ValueError('parameters must is string')
        
    def check_index(index):
        if index < 5:
            raise IndexError('index must greater than 10')
    
    class Super_List(list):
        def __init__(self):
            super(Super_List, self).__init__()      # 调用父类初始化
            self += [None] * 5                      # 对初始化的参数进行修改
    
        def append(self, *args):                    # 对append进行参数限制
            for i in args:
                check_str(i)
            return super(Super_List, self).append(*args)
    
        def insert(self, index, *args):              # 对insert的参数(索引及插入元素)进行限制
            check_index(index)  # 判断插入位置
            for i in args:
                check_str(i)
            return super(Super_List, self).insert(index, *args)
    
        def extend(self, *args):                    # 对扩张的列表元素进行判断
            temp = args[0]
            for i in temp:
                check_str(i)
            super(Super_List, self).extend(*args)
        
        def __delitem__(self, index):                # 对del命令的索引进行判断
            check_index(index)
            super(Super_List, self).__delitem__(index)
    
        def clear(self):                            # 禁止使用clear命令
            raise TypeError('No permission')
    
    ss_l = Super_List()
    print(ss_l)
    ss_l.append('1')
    ss_l.insert(5, 'a')
    ss_l.extend(['a', 'b', 'c'])
    ss_l.clear()
    print(ss_l)
    

     写了快半个小时,感觉列表的增加与删除命令很多,所有有一些命令没有重写,但逻辑还是一样的。

    如果向在有人访问参数的时候,自动执行某些命令,可以写在__getitem__下面。

    跟新后,添加一个__missing__感觉还是非常有意思的。

    class Dict(dict):
        def __init__(self, *args, **kwargs):
            # self.x = 12
            super(Dict, self).__init__(*args, **kwargs)
    
        def __missing__(self, key):
            self[key] = None
            return self[key]
    
    
    l = Dict(((1,2),(2,3)))
    print(l)
    print(l[8])
    print(l)
    
    {1: 2, 2: 3}
    None
    {1: 2, 2: 3, 8: None}
    

     有点像字典的内置方式setdefault,我看能不能改成一样的。

    已经写完了,通过[]取值。

    # -*- coding: utf-8 -*-
    
    class Dict(dict):
        def __init__(self, *args, **kwargs):
            super(Dict, self).__init__(*args, **kwargs)
    
        def __missing__(self, item):
            # 判断进来的参数是不是字符串,如果是字符串说明就是对象主动调用__missing__进来的
            # 非__getitem__导入的
            if isinstance(item, str):
                self[item] = 'Default Empty'
                return self[item]
            # 如果对象非字符串,明显说明是__getitem__导入的,判断长度就可以
            else:
                key, value = item
                self[key] = value     # 自身进行赋值
                return self[key]      # 返回value
    
    
        def __getitem__(self, item):
            if not isinstance(item, tuple):    # 传进来的item进行判断,如果非元祖,直接调用父类绑定self方法返回
                return super(Dict, self).__getitem__(item)
            elif len(item) == 2 and isinstance(item, tuple):   # 如果是元祖,又是2位长度的,进行赋值。其实感觉元祖判断没有好像也没关系
                k, _ = item
                if k in self:
                    return super(Dict, self).__getitem__(k)      # 如果k在self里面继续调用父类绑定self方法返回
                else:
                    res = self.__missing__(item)             # 否则调用自身的__missing
                    return res
            else:
                raise TypeError('input pattern error')          # 元素数量超过2个,直接报错
    
    
    
    
    l = Dict((('name','sidian'),('age',99)))
    
    print(l)
    print(l['name','wudian'])
    print(l['addr','杭州'])
    print(l['hobby'])
    print(l)
    {'name': 'sidian', 'age': 99}
    sidian
    杭州
    Default Empty
    {'name': 'sidian', 'age': 99, 'addr': '杭州', 'hobby': 'Default Empty'}
  • 相关阅读:
    技术专题:ROS通过TTL值来防止二层路由的最简单办法
    唉,一大早起床遇到脑残的,实在无语!QQ:124316912
    简单描述FTTH方案中EPON、GPON设置的优势、原理及城中村的解决方案
    9.9成新WAYOS、HZZ、ROS软件路由WAN扩展交换机大量到货只需450
    辅助工具:免输入命令,WAYOS通过交换机一键扩展WAN口工具
    配置文档:3COM 4200 3C17300A配置文件,可与WAYOS、ROS、海蜘蛛多WAN对接
    网站页面跳转代码大全,网站网页跳转代码
    popupWin 属性及用法介绍 ASP.NET控件,仿QQ,msn右下角弹出窗口
    IIS打开ASP文件出现Server Application Error提示的解决方法,本人亲历,成功
    教你学会提高无线网下载速度的方法
  • 原文地址:https://www.cnblogs.com/sidianok/p/11790087.html
Copyright © 2011-2022 走看看