Dealing with mypy @overload
I wanted to have something like enum
but for types.
在处理mypy@overload时,我想有一些类似enum的东西,但对于类型。
You see, I deal with mpi4py
and there is an argument tag
that does nothing very useful, just separates messages (so that a receiver can know what data it is).
你看,我处理mpi4py,有一个参数标签,它没有什么用处,只是分离消息(这样接收者就可以知道它是什么数据)。
With different tags I send different data, types of data, but it is not even checked by the code editor, and I can get confused if I accidentally send data with a wrong tag.
使用不同的标签,我发送不同的数据,数据类型,但代码编辑器甚至没有检查它,如果我不小心发送了带有错误标签的数据,我可能会感到困惑。
My plan was to define a special function to send data
我的计划是定义一个特殊的函数来发送数据
from typing import Tuple, Dict, Union, overload
from mpi4py import MPI
MPIComm = Union[MPI.Intracomm, MPI.Intercomm]
class TAG_NUMERIC:
tag = 1
class TAG_STRING
tag = 2
class TAG_DICT_STR_INT:
tag = 3
class TAG_DICT_STR_TUPLE_INT_INT:
tag = 4
@overload
def send(mpi_comm: MPIComm, dest: int, data: int, tag: TAG_NUMERIC) -> None: ...
@overload
def send(mpi_comm: MPIComm, dest: int, data: str, tag: TAG_STRING) -> None: ...
@overload
def send(mpi_comm: MPIComm, dest: int, data: Dict[str, int], tag: TAG_DICT_STR_INT) -> None: ...
@overload
def send(mpi_comm: MPIComm, dest: int, data: Dict[str, Tuple[int, int]], tag: TAG_DICT_STR_TUPLE_INT_INT) -> None: ...
def send(mpi_comm, dest, data, tag):
mpi_comm.send(obj=data, dest=dest, tag=tag)
And call it this way:
这样称呼它:
some_int = 5
send(mpi_comm, 1, some_int, TAG_NUMERIC.tag)
some_string = 'abcd'
send(mpi_comm, 1, some_string, TAG_STRING.tag)
some_simple_dict = {"key1": 1, "key2": 2}
send(mpi_comm, 1, some_simple_dict, TAG_DICT_STR_INT.tag)
some_advanced_dict = {"key1": (1, 2), "key2": (3, 4)}
send(mpi_comm, 1, some_advanced_dict, TAG_DICT_STR_TUPLE_INT_INT.tag)
But it is so "not clever" to write so many lines to just define another type with a corresponding type in the class name.
但是,写这么多行来定义另一个具有类名中相应类型的类型是非常“不聪明”的。
Is there a possible way to define something like enum
but for types (classes), those classes would contain only a single constant? Something like
有没有可能定义类似enum的东西,但对于类型(类),这些类只包含一个常量?类似于
class TAGS(int, typeEnum):
HOUSE_NUMBER = 1 # corresponding data type: int
STREET_NAME = 2 # corresponding data type: str
NAMES_AND_AGES = 3 # corresponding data type: Dict[str, int]
SOMETHING = 4 # corresponding data type: Dict[str, Tuple[int, int]]
And use it
并使用它
var = TAGS.SOMETHING.value
print(var) # output: 4
type(var) # output: TAGS.SOMETHING
更多回答
Why not just have separate methods for each type? That would give a type checker more information to work with and might improve readability, at the cost of writing slightly more code.
为什么不为每种类型都有单独的方法呢?这将为类型检查器提供更多的信息,并可能提高可读性,但代价是编写更多的代码。
@SamMason First, it will be illogical from the point of view of the functions' purpose - to reduce the amount of repeated code, and second, the functions will have rather strange names. However, your method is the same as my method of writing a lot of lines of code with class definitions, and it is not clear which of the two methods is better. Nevertheless, for me the amount of handwritten code comes first.
@SamMason首先,从函数的目的来看,这是不合逻辑的——减少重复代码的数量;其次,函数的名称会很奇怪。然而,您的方法与我编写大量带有类定义的代码行的方法相同,并且不清楚这两种方法中哪一种更好。然而,对我来说,手写代码的数量是第一位的。
Why not add a wrapper func that tests the type of what you’re sending and figures out the tag? tag = {int : inttag}[type(data)]
? Thats probably what overload is doing anyway.
为什么不添加一个包装函数来测试你发送的内容的类型并计算出标签呢?tag={int:intag}[类型(数据)]?无论如何,这可能就是超负荷工作的结果。
Using the example in your question, what's wrong with send_house_number(mpi_comm, 1, some_int)
? Note that if you want to set up lots of methods like this, you can write a higher order function that would let you do something like send_house_number = make_sender(int)
.
使用问题中的示例,send_house_number(mpi_comm,1,some_int)有什么问题?注意,如果你想设置很多这样的方法,你可以写一个更高阶的函数,让你做一些类似send_house_number=make_sender(int)的事情。
You can define a class dynamically with the type()
. So, you can do like this.
您可以使用type()动态定义一个类。所以,你可以这样做。
from enum import IntEnum
class TAG(IntEnum):
NUMERIC = 1
STRING = 2
for k, v in TAG.__members__.items():
cls_name = 'TAG_' + k
globals()[cls_name] = type(cls_name, (), dict(tag=v.value))
print(TAG_NUMERIC, TAG_NUMERIC.tag)
# This will print "<class '__main__.TAG_NUMERIC'> 1".
更多回答
Your method is interesting, but at runtime, Python does not perform type checks. And the biggest problem is that static checkers know nothing about this type, so they will indicate that this type does not exist. I need to have a statically resolvable method.
您的方法很有趣,但在运行时,Python不执行类型检查。最大的问题是静态检查器对这种类型一无所知,所以他们会指示这种类型不存在。我需要一个静态可解析的方法。
@MPEI_stud, you need to edit your question for that requirement on type checkers. Anyway, there's no built-in Python syntax for that. A possible workaround is to write a code generator which writes a conventional code that type checkers can understand.
@MPEI_stud,您需要根据类型检查器的要求编辑您的问题。无论如何,没有内置的Python语法。一个可能的解决方法是编写一个代码生成器,它可以编写类型检查器能够理解的传统代码。
我是一名优秀的程序员,十分优秀!