4.自定义序列类

1. 序列类的分类

143359_C2dx_3836952.png

2.序列的+、+=、extend方法

+与+=的用法区别

代码:

# 常用用法
>>> a = [1, 2]
>>> c = a + [3, 4]
>>> print(c)
[1, 2, 3, 4]

>>> a += [3, 4]
>>> print(a)
[1, 2, 3, 4]

# 区别之处
>>> a += (5, 6)
>>> print(a)
[1, 2, 3, 4, 5, 6]


>>> d = c + (5, 6)
>>> print(c)
Traceback (most recent call last):
  File "1_swquence_test.py", line 17, in <module>
    d = c + (5, 6)
TypeError: can only concatenate list (not "tuple") to list

上述代码中 我们可以发现,list的 +和+= 后面都可以加list。 可是如果后面接的set, +=也没问题,但+就会报错。+=是通过什么方法实现这样的效果的呢?

  1. 查看定义 _collections_abc 下的MutableSequence
  2. MutableSequence中有个魔法函数__iadd__
   def __iadd__(self, values):
        self.extend(values)
        return self
  1. 再查看extend方法
def extend(self, values):
        'S.extend(iterable) -- extend sequence by appending elements from the iterable'
        for v in values:
            self.append(v)

这个extend传入的values只要是iterable可迭代类型就行,然后这个extend函数会for遍历values一个个地加入self。

extend函数传入的参数只要是可迭代的类型,就可以实现。而+=之所以能把tuple加入list中,本质上就是调用类extend方法

extend与append的区别

一段代码就可以明白

>>> d1 = [1, 2, 3]
>>> d2 = [1, 2, 3]

>>> d1.extend((1, 2, 3))
>>> print(d1)
[1, 2, 3, 1, 2, 3]


>>> d2.append((1, 2, 3))
>>> print(d2)
[1, 2, 3, (1, 2, 3)]

3. 实现可切片对象

切片的用法

代码举例:

# 模式[start:end:step]
"""
    其中,第一个数字start表示切片开始位置,默认为0;
    第二个数字end表示切片截止(但不包含)位置(默认为列表长度);
    第三个数字step表示切片的步长(默认为1)。
    当start为0时可以省略,当end为列表长度时可以省略,
    当step为1时可以省略,并且省略步长时可以同时省略最后一个冒号。
    另外,当step为负整数时,表示反向切片,这时start应该比end的值要大才行。
"""
aList = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
print(aList[::])  # 返回包含原列表中所有元素的新列表
print(aList[::-1])  # 返回包含原列表中所有元素的逆序列表
print(aList[::2])  # 隔一个取一个,获取偶数位置的元素
print(aList[1::2])  # 隔一个取一个,获取奇数位置的元素
print(aList[3:6])  # 指定切片的开始和结束位置
aList[0:100]  # 切片结束位置大于列表长度时,从列表尾部截断
aList[100:]  # 切片开始位置大于列表长度时,返回空列表

aList[len(aList):] = [9]  # 在列表尾部增加元素
aList[:0] = [1, 2]  # 在列表头部插入元素
aList[3:3] = [4]  # 在列表中间位置插入元素
aList[:3] = [1, 2]  # 替换列表元素,等号两边的列表长度相等
aList[3:] = [4, 5, 6]  # 等号两边的列表长度也可以不相等
aList[::2] = [0] * 3  # 隔一个修改一个
print(aList)
aList[::2] = ['a', 'b', 'c']  # 隔一个修改一个
aList[::2] = [1, 2]  # 左侧切片不连续,等号两边列表长度必须相等
aList[:3] = []  # 删除列表中前3个元素

del aList[:3]  # 切片元素连续
del aList[::2]  # 切片元素不连续,隔一个删一个

如何自己做一个可以切片的对象?

我们可以模仿 _collections_abc模块中Sequence不可改变的序列, (如果想实现可变序列, 可以模仿MutableSequence)

代码:

class Group:
    # 支持切片操作
    def __init__(self, group_name, company_name, staffs):
        self.group_name = group_name
        self.company_name = company_name
        self.staffs = staffs

    def __reversed__(self):   # reversed(list)会调用该方法
        pass

    def __getitem__(self, item):   # 实现切片
        cls = type(self)    # 相当于cls=Group()  但软编程可维护性好
        if isinstance(item, slice):   # sub_group = group[:2]时进入
            return cls(group_name=self.group_name, company_name=self.company_name, staffs=self.staffs[item])
        elif isinstance(item, numbers.Integral):  # g0 = group[0]时进入
            return cls(group_name=self.group_name, company_name=self.company_name, staffs=[self.staffs[item]])

    def __len__(self):
        pass

    def __iter__(self):
        pass

    def __contains__(self, item):     #  for in  时会调用
        pass


staffs = ['cannon1', 'cannon2', 'cannon3', 'cannon4']
group = Group(company_name='company', group_name='user', staffs=staffs)
sub_group = group[:2]   # debug时 可以查看内部情况
g0 = group[0]

4. bisect维护排序序列

bisect 可以用来处理已排序的序列
进行排序时, 用二分查找算法,效率高。

代码:

>>> import bisect

>>> inter_list = []   # 只要是可修改的序列类型  如 collections的deque等
>>> bisect.insort(inter_list, 3)
>>> bisect.insort(inter_list, 2)
>>> bisect.insort(inter_list, 5)
>>> bisect.insort(inter_list, 1)
>>> bisect.insort(inter_list, 6)
>>> print(inter_list)  # 得到的序列是排序好的,效率高

[1, 2, 3, 5, 6]

>>> print(bisect.bisect(inter_list, 3))   # 用来做查找的 在3后面的位置 就是bisect_right
3

>>> print(bisect.bisect_left(inter_list, 3))  # 用来做查找的 在3前面的位置
2

5. 什么情况下,我们不该使用列表list?

array 等于是c语言的数组
array和list的重要区别:
- array:  只能存放指定的数据类型
- list:   什么都能放,灵活,但效率没array高
>>> import array

>>> my_array = array.array('i')  # i表示 signed integer 类型
>>> my_array.append(1)
>>> my_array.append(2)
>>> my_array.append(3)
>>> my_array.append(4)
>>> print(my_array)
array('i', [1, 2, 3, 4])

>>> my_array.append('abc')   # 传入的不是指定类型,就会报错

Traceback (most recent call last):
  File "5_array.py", line 4, in <module>
    my_array = array.array(9)
TypeError: array() argument 1 must be a unicode character, not int

6. 列表推导式、生成器推导式、字典推导式、集合推导式

列表推导式(或称为列表生成式):
# 列表生成式
# 1. 提取1-20中的奇数
# 列表操作, 效率比列表生成式低很多
>>> odd_list1 = []
>>> for i in range(21):
>>>     if i % 2 == 1:
>>>         odd_list1.append(i)
>>> print(odd_list1)
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

# 换成列表推导式
>>> odd_list2 = [i for i in range(21) if i % 2 == 1]
>>> print(odd_list2)
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]


# 2. 复杂逻辑的情况
>>> def hadle_item(item):
>>>     return item * item

>>> odd_list3 = [hadle_item(i) for i in range(21) if i % 2 == 1]   
>>> print(odd_list3)
[1, 9, 25, 49, 81, 121, 169, 225, 289, 361]
生成器表达式:
# 生成器表达式
>>> odd_gen = (i for i in range(21) if i % 2 ==1)
>>> print(type(odd_gen))
<class 'generator'>

>>> odd_list = list(odd_gen)
>>> print(type(odd_list))
<class 'list'>

>>> print(odd_list)
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
字典推导式:
# 字典推导式
>>> my_dict = {'cannon1':22, 'cannon2':23, 'cannon3':24}
# value变为value^2
>>> reversed_dict = {key:value*value for key, value in my_dict.items()}
>>> print(reversed_dict)
{'cannon1': 484, 'cannon2': 529, 'cannon3': 576}

# key 和 value交换位置
>>> reversed_dict = {value:key for key, value in my_dict.items()}
>>> print(reversed_dict)
{22: 'cannon1', 23: 'cannon2', 24: 'cannon3'}

集合推导式:

# 集合推导式
>>> my_dict = {'cannon1':22, 'cannon2':23, 'cannon3':24}
>>> my_set = {key for key , value in my_dict.items()}    # .items()不要忽略 
# 取巧法:  my_set = set(my_dict.keys())    但这方法灵活性不够

>>> print(type(my_set))
<class 'set'>

>>> print(my_set)  # 得到了想要的集合
{'cannon1', 'cannon2', 'cannon3'}

转载于:https://my.oschina.net/u/3836952/blog/1823381

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值