以SortedList为例详解Python的defaultdict对象使用自定义类型的方法

目录
  • 写在前面
  • 第一种方法: 封装成函数
  • 第二种方法: 类封装

写在前面

最近写周赛题, 逃不开的一种题型是设计数据结构, 也就是第三题, 做这种题需要的就是对语言中的容器以及常用排序查找算法的掌握, 而我只熟悉了最基本的一些方法, 做起这些题来总是超时…

为了搞定这些题, 我决定学习一下大佬们的做法, 特别是优先队列的方法维护有序容器以及有序列表等容器, 这些都在Python中封装好了, 用起来很是方便, 但是采用defaultdict的时候, 其缺省数据类型常常需要与题目给出的特定结构匹配, 这就需要定义一个新的数据类型, 下面我就以一种十分常用的结构SortedList为例, 设置自定义的数据类型(本例为将默认的升序列表变成降序列表).

其他的数据结构当然也可以根据下面列出的方法来改, 主要知识点就是函数与类的运用了

第一种方法: 封装成函数

首先导入需要的函数, 其中neg方法可以用lambda x: -x代替, 本质上是一样的, 下面写的代码这两种均可.

from collections import defaultdict
from sortedcontainers import (SortedList as SL, SortedKeyList as SKL)
from operator import neg  # or `lambda x: -x`

然后我们来看第一种方法, 其实封装成函数本质上就是将自定义对象作为函数返回值, 下面给出两种实现, 其实不传入参数也可以, 但是这样的话下面的第15行就不能使用了, 只能通过add()来添加值, 还是有局限的.

代码中的d2直接用一个新的lambda函数, 定义键, 就不需要考虑直接初始化失效的情况.

def reverseSL(x=None):
    return SL(iterable=x, key=lambda x: -x)

def reverseSL1_no_args():
    return SL(key=lambda x: -x)

d1 = defaultdict(reverseSL)
d2 = defaultdict(lambda: SL(key=neg))

data = [3, 2, 4, 1]
for i in data:
    d1[1].add(i)
    d2[1].add(i)
# 也可以直接加入排序列表
d1[2] = reverseSL([1, 2])
d2[2] = reverseSL([1, 2])
print(d1)
print(d2)

可以得到如下的结果:

defaultdict(<function reverseSL at 0x100a680d0>, {1: SortedKeyList([4, 3, 2, 1], key=<function reverseSL.<locals>.<lambda> at 0x100c659d0>), 2: SortedKeyList([2, 1], key=<function reverseSL.<locals>.<lambda> at 0x100caa550>)})
defaultdict(<function <lambda> at 0x100c65820>, {1: SortedKeyList([4, 3, 2, 1], key=<built-in function neg>), 2: SortedKeyList([2, 1], key=<function reverseSL.<locals>.<lambda> at 0x100cb9940>)})
[Finished in 214ms]

如果第15行改为:

d1[2] = reverseSL_no_args([1, 2])

就会提示:TypeError: reverseSL_no_args() takes 0 positional arguments but 1 was given, 但是add()方法不会有问题.

第二种方法: 类封装

这种方法比较复杂, 并且有一个小坑, 这里先看第一个类的代码.

我这里实现了两个类, 其中mySL1采用的是组合的面向对象设计方法, mySL2用的是继承. 第一种代码比较多, 因为里面添加了一个组件SortedList, 就需要重写add().

class mySL1:
    def __init__(self, iterable=None):
        self.sl = SL(iterable=iterable, key=lambda x: -x)
    def add(self, item):
        self.sl.add(item)
    def get(self):
        return list(self.sl)
    def __repr__(self):
        return repr(self.sl)

其中的__repr__是可选的, 只是为了清楚地显示已加入到defaultdict的数据情况. 不写的话还得调用get()方法, 进行字典值(values)数据的输出, 这里为方便就直接转换为List类型了, 如果不转换, 没办法在类外通过list()进行转换, 因为这样得到的数据不是可迭代对象, 通过直接输出值的类型, 可以得到<class '__main__.mySL1'>.

然后是第二个类, 继承语法简洁明了, 直接调用父类的初始化方法, 但是这里需要注意的是, 继承SortedList类的代码这里就不能用了, 因为如果还是使用SortedList, 在__init__中修改key就会提示断言错误, assert key is None, 这个问题让我比较困惑, 甚至觉得可能继承的方法行不通,(下面是模块的__new__方法的源码) 我知道了问题的所在.

    def __new__(cls, iterable=None, key=None):
        """Create new sorted list or sorted-key list instance.
        Optional `key`-function argument will return an instance of subtype
        :class:`SortedKeyList`.
        >>> sl = SortedList()
        >>> isinstance(sl, SortedList)
        True
        >>> sl = SortedList(key=lambda x: -x)
        >>> isinstance(sl, SortedList)
        True
        >>> isinstance(sl, SortedKeyList)
        True
        :param iterable: initial values (optional)
        :param key: function used to extract comparison key (optional)
        :return: sorted list or sorted-key list instance
        """
        # pylint: disable=unused-argument
        if key is None:
            return object.__new__(cls)
        else:
            if cls is SortedList:
                return object.__new__(SortedKeyList)
            else:
                raise TypeError('inherit SortedKeyList for key argument')

这里模块的作者提供了一个SortedList的子类, 叫做SortedKeyList, 顾名思义, 就是提供了一种可以写入key的类, 这时候继承这个类就不会有问题了.

其实在上面的函数调用那块, 就已经有所提示, 输出结果中的类型, 就显示是SortedKeyList, 这个类型就是修改了key(使得key is not None)之后得到的对象. 大家可以尝试一下, 如果不修改key, 就还是SortedList.

class mySL2(SKL):
    """use SortedKeyList instead SortedList,
    because SortedList cannot init argument `key`,
    `assert key is None` in its `__init__`"""

    def __init__(self, iterable=None):
        super().__init__(iterable=iterable, key=neg)

最后是创建defaultdict, 以及数据的读取:

d3 = defaultdict(mySL1)
d4 = defaultdict(mySL2)
for i in [19, 11, 12, 123]:
    d3['x'].add(i)
    d4['y'].add(i)
# 或者直接通过列表初始化
d3['z'] = mySL1([1, 2])
d4['w'] = mySL2([1, 2])
print(d3)
print(d4)
print(d3['x'].get(), d3['z'].get())
print(list(d4['y']), list(d4['w']))

可以得到下面的结果:

defaultdict(<class '__main__.mySL1'>, {'x': SortedKeyList([123, 19, 12, 11], key=<function mySL1.__init__.<locals>.<lambda> at 0x1008e40d0>), 'z': SortedKeyList([2, 1], key=<function mySL1.__init__.<locals>.<lambda> at 0x100bebd30>)})
defaultdict(<class '__main__.mySL2'>, {'y': mySL2([123, 19, 12, 11], key=<built-in function neg>), 'w': mySL2([2, 1], key=<built-in function neg>)})
[123, 19, 12, 11] [2, 1]
[123, 19, 12, 11] [2, 1]

可以看出, 第一种类的创建, 其实最后还是用到了SortedKeyList这个子类.

到此这篇关于以SortedList为例详解Python的defaultdict对象使用自定义类型的方法的文章就介绍到这了,更多相关Python defaultdict内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python中的defaultdict与__missing__()使用介绍

    前言 今天我们的主角是 defaultdict ,同时也会介绍一下模仿方法 __missing__() ,本文主要来源于网友博客,分享给有需要的人.下面话不多说了,来一起看看详细的介绍吧. 默认值可以很方便 众所周知,在Python中如果访问字典中不存在的键,会引发KeyError异常.但是有时候,字典中的每个键都存在默认值是非常方便的.例如下面的例子: strings = ('puppy', 'kitten', 'puppy', 'puppy', 'weasel', 'puppy', 'kit

  • 在Python中使用defaultdict初始化字典以及应用方法

    Python中可以使用collections中的defaultdict类实现创建进行统一初始化的字典.这里总结两种常用一点的初始化方式,分别是初始化为list和int. 初始化为list示范代码: #!/usr/bin/python from collectionsimport defaultdict s = [('yellow',1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] d =defaultdict(list) for k

  • Python中defaultdict与lambda表达式用法实例小结

    本文实例讲述了Python中defaultdict与lambda表达式用法.分享给大家供大家参考,具体如下: 从教程中看到defaultdict是一个类,在一台装有Python2.7.6的电脑上使用发现不存在.在文档中搜索了一下也没有找到,想当然以为这或许是Python 3.X专有的.因为教程就是基于Python 3.X实现的.后来换了一台装有Python 3.X的电脑依然出问题. 求助于网络,发现这个类其实是collections模块中的一个类.看来,学习很难摆脱网络环境啊! 这个类是dict

  • Python collections.defaultdict模块用法详解

    Python中通过Key访问字典,当Key不存在时,会引发'KeyError'异常.为了避免这种情况的发生,可以使用collections类中的defaultdict()方法来为字典提供默认值. 语法格式: collections.defaultdict([default_factory[, -]]) class defaultdict(Dict[_KT, _VT], Generic[_KT, _VT]): default_factory: Callable[[], _VT] 该函数返回一个类似

  • python中defaultdict的用法详解

    初识defaultdict 之前在使用字典的时候, 用的比较随意, 只是简单的使用dict. 然而这样在使用不存在的key的时候发生KeyError这样的一个报错, 这时候就该defaultdict登场了. 如何使用defaultdict 可以这样 from collections import defaultdict d1 = defaultdict(int) 或者这样 import collections d1 = collections.defaultdict(int) defaultdi

  • python中defaultdict字典功能特性介绍

    defaultdict是普通字典dict的一个子类.通过collections库的defaultdict()方法创建.defaultdict()需要传入的参数为 类名.(type类型)首先,以int类 作为参数传入为例, from collections import defaultdict dedict = defaultdict(int) print(dedict) 不同于普通的字典,其特性在于,当用一个defaultdict中不存在的键来调用时,不会报KeyError错误 以调取’a’键的

  • 详解Python 中的 defaultdict 数据类型

    这篇文章给大家介绍Python 中的 defaultdict 数据类型,具体内容如下所示: 官方网址 首先,defaultdict 是 dict 的一个子类.通常 Python 中字典(dict)这种数据类型是通过键值对来存取的,当索引一个不存在的键时,就会引发 keyerror 异常.那么,defaultdict 就可以解决这个问题,它可以实现为不存的键值返回一个默认值. defaultdict是 collections 包下的一个模块,defaultdict 在初始化时可以提供一个 defa

  • 以SortedList为例详解Python的defaultdict对象使用自定义类型的方法

    目录 写在前面 第一种方法: 封装成函数 第二种方法: 类封装 写在前面 最近写周赛题, 逃不开的一种题型是设计数据结构, 也就是第三题, 做这种题需要的就是对语言中的容器以及常用排序查找算法的掌握, 而我只熟悉了最基本的一些方法, 做起这些题来总是超时… 为了搞定这些题, 我决定学习一下大佬们的做法, 特别是优先队列的方法维护有序容器以及有序列表等容器, 这些都在Python中封装好了, 用起来很是方便, 但是采用defaultdict的时候, 其缺省数据类型常常需要与题目给出的特定结构匹配,

  • 详解 Python 与文件对象共事的实例

    详解 Python 与文件对象共事的实例 Python 有一个内置函数,open,用来打开在磁盘上的文件.open 返回一个文件对象,它拥有一些方法和属性,可以得到被打开文件的信息,以及对被打开文件进行操作. >>> f = open("/music/_singles/kairo.mp3", "rb") (1) >>> f (2) <open file '/music/_singles/kairo.mp3', mode 'r

  • 详解Python读取和写入操作CSV文件的方法

    目录 什么是 CSV 文件? 内置 CSV 库解析 CSV 文件 读取 CSV 文件csv 将 CSV 文件读入字典csv 可选的 Python CSV reader参数 使用 csv 写入文件 从字典中写入 CSV 文件csv 使用 pandas 库解析 CSV 文件 pandas 读取 CSV 文件 pandas 写入 CSV 文件 最流行的数据交换格式之一是 CSV 格式.是需要通过键盘和控制台以外的方式将信息输入和输出的程序,通过文本文件交换信息是在程序之间共享信息的常用方法. 这里带和

  • 详解Python中pyautogui库的最全使用方法

    在使用Python做脚本的话,有两个库可以使用,一个为PyUserInput库,另一个为pyautogui库.就本人而言,我更喜欢使用pyautogui库,该库功能多,使用便利.下面给大家介绍一下pyautogui库的使用方法.在cmd命令框中输入pip3 install pyautogui即可安装该库! 常用操作 我们在pyautogui库中常常使用的方法,如下: import pyautogui pyautogui.PAUSE = 1 # 调用在执行动作后暂停的秒数,只能在执行一些pyaut

  • 详解Python类和对象内容

    目录 一.什么是Python类? 二.Python类中的方法和属性 2.1.Python类中的方法 2.2.Python类中的属性 三.面向对象的概念 3.1.Python类:继承 3.2.Python类:多态性 3.3.Python类:抽象 一.什么是Python类? python中的类是创建特定对象的蓝图.它使您可以以特定方式构建软件.问题来了,怎么办?类允许我们以一种易于重用的方式对我们的数据和函数进行逻辑分组,并在需要时进行构建.考虑下图. 在第一张图片(A)中,它代表了一个可以被视为C

  • 实例详解python函数的对象、函数嵌套、名称空间和作用域

    函数的对象 python中一切皆对象 函数对象的四大功能 引用 def f1(): print('from f1') f1() #调用函数 print(f1) print('*'*50) f = f1 # 将函数名f1赋值给f f() # f也可以调用函数 print(f) from f1 <function f1 at 0x000001FB05534620> ************************************************** from f1 <func

  • 详解Python用三种方式统计词频的方法

    三种方法: ①直接使用dict ②使用defaultdict ③使用Counter ps:`int()`函数默认返回0  ①dict text = "I'm a hand some boy!" frequency = {} for word in text.split(): if word not in frequency: frequency[word] = 1 else: frequency[word] += 1  ②defaultdict import collections f

  • 详解Python中内置的NotImplemented类型的用法

    它是什么? >>> type(NotImplemented) <type 'NotImplementedType'> NotImplemented 是Python在内置命名空间中的六个常数之一.其他有False.True.None.Ellipsis 和 __debug__.和 Ellipsis很像,NotImplemented 能被重新赋值(覆盖).对它赋值,甚至改变属性名称, 不会产生 SyntaxError.所以它不是一个真正的"真"常数.当然,我们应

  • 详解Python中列表和元祖的使用方法

    list Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出班里所有同学的名字,就可以用一个list表示: >>> classmates = ['Michael', 'Bob', 'Tracy'] >>> classmates ['Michael', 'Bob', 'Tracy'] 变量classmates就是一个list.用len()函数可以获得list元素的个数: >>> len(c

  • 详解Python判定IP地址合法性的三种方法

    IP合法性校验是开发中非常常用的,看起来很简单的判断,作用确很大,写起来比较容易出错,今天我们来总结一下,看一下3种常用的IP地址合法性校验的方法. IPv4的ip地址格式:(1~255).(0~255).(0~255).(0~255) 方法1: 正则表达式判定法 最简单的实现方法是构造一个正则表达式.判断用户的输入与正则表达式是否匹配.若匹配则是正确的IP地址,否则不是正确的IP地址. 复制代码 代码如下: ^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\.(

随机推荐