可散列、可调用数据类的 Python 类型提示

如何解决可散列、可调用数据类的 Python 类型提示

我想编写一个 Python 函数,它将 Callable 对象和相应的参数作为输入,并返回从 Callable 对象到这些对象在参数上的值的映射。更具体地说,代码可能如下所示。

>>> import collections
>>> import dataclasses
>>> from typing import Iterable,List,Mapping
>>> @dataclasses.dataclass(frozen=True)
... class Adder:
...     x: int = 0
...     def __call__(self,y: int) -> int:
...             return self.x + y
... 
>>> def fn_vals(fns: Iterable[Adder],vals: Iterable[int]) -> Mapping[Adder,List[int]]:
...     values_from_function = collections.defaultdict(list)
...     for fn in fns:
...             for val in vals:
...                     values_from_function[fn].append(fn(val))
...     return values_from_function
... 
>>> fn_vals((Adder(),Adder(2)),(1,2,3))
defaultdict(<class 'list'>,{Adder(x=0): [1,3],Adder(x=2): [3,4,5]})

但是,我正在努力让它与更广泛的 Callable 对象类别一起使用。特别是,以下失败并显示 __hash__ 尚未实现的错误。

>>> import dataclasses
>>> from typing import Callable,Hashable
>>> class MyFunctionInterface(Callable,Hashable): pass
... 
>>> @dataclasses.dataclass(frozen=True)
... class Adder(MyFunctionInterface):
...     x: int = 0
...     def __call__(self,y: int) -> int:
...             return self.x + y
... 
>>> Adder()
Traceback (most recent call last):
  File "<stdin>",line 1,in <module>
  File "/home/alex/anaconda3/lib/python3.7/typing.py",line 814,in __new__
    obj = super().__new__(cls)
TypeError: Can't instantiate abstract class Adder with abstract methods __hash__

我想修改我的 fn_vals 函数,使 fns 具有 Iterable[MyFunctionInterface] 类型,因为我需要 fns 的元素具有的唯一属性是它们是 CallableHashable。有没有办法表明数据类满足 MyFunctionInterface,并且 __hash__ 函数仍然由 dataclass 装饰器生成?

解决方法

这里的问题是 abc 和类装饰器之间的不良交互。

引用 abc docs,

不支持向类动态添加抽象方法,或在方法或类创建后尝试修改其抽象状态。

一旦一个类被创建,你就不能改变它的抽象性。不幸的是,像 dataclasses.dataclass 这样的类装饰器会在类已经创建之后开始使用。

最初创建 Adder 时,它没有 __hash__ 实现。 abc 此时会检查该类并确定该类是抽象类。然后,装饰器将 __hash__ 和所有其他数据类内容添加到类中,但为时已晚。

您的类确实有一个 __hash__ 方法,但 abc 机制不知道这一点。


至于如何进行,有两个主要选项。一种是完全消除 MyFunctionInterface,只是将您的可调用散列对象注释为 Any。第二个是,假设您希望您的对象可以使用单个 int 参数专门调用并返回一个 int,您可以定义一个协议

class MyProto(typing.Protocol):
    def __call__(self,y: int) -> int: ...
    def __hash__(self) -> int: ...

然后将您的对象注释为 MyProto

,

docs

中所述

默认情况下,dataclass() 不会隐式添加 __hash__() 方法,除非这样做是安全的。它也不会添加或更改现有的显式定义的 __hash__() 方法。设置类属性 __hash__ = None 对 Python 具有特定含义,如 __hash__() 文档中所述。

看起来 Hashable 定义了 __hash__ 方法,因此数据类不会显式定义 __hash__。因此,创建扩展 MyFunctionInterface 的新类并设置 __has__ = None 并使用它扩展加法器。

import dataclasses
from typing import Callable,Hashable
class MyFunctionInterface(Callable,Hashable): pass

class MyFunctionInterfaceHashed(MyFunctionInterface):
    __hash__ = None

@dataclasses.dataclass(frozen=True)
class Adder(MyFunctionInterfaceHashed):
    x: int = 0

    def __call__(self,y: int) -> int:
        return self.x + y

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res