【发布时间】:2020-07-31 00:48:19
【问题描述】:
为了更好的设计和 OOP,我想创建一个自定义的 IDE 兼容的静态类型。例如,考虑以下理想化类:
class IntOrIntString(Union[int, str]):
@staticmethod
def is_int_string(item):
try:
int(item)
return True
except:
return False
def __instancecheck__(self, instance):
# I know __instacecheck__ is declared in the metaclass. It's written here for the sake of the argument.
return isinstance(instance, int) or (isinstance(instance, str) and self.is_int_string(instance))
@staticmethod
def as_integer(item):
return int(item)
现在,我知道这是一个愚蠢的课程,但它只是一个简单的例子。定义这样的类有以下好处:
- 它允许在 IDE 中进行静态类型检查(例如
def parse(s: IntOrIntString): ...)。 - 它允许动态类型检查(例如
isinstance(item, IntOrIntString))。 - 它可以用来更好地封装类型相关的静态函数(例如
inetger = IntOrIntString.as_integer(item))。
但是,此代码不会运行,因为 Union[int, str] 不能被子类化 - 我明白了:
TypeError: 不能子类化 typing.Union
所以,我试图通过创建这个“类型”来解决这个问题,将它称为Union 的实例(实际上是)。含义:
IntOrIntString = Union[int, str]
IntOrIntString.as_integer = lambda item: int(item)
...
但是当我收到错误消息时这也不起作用
AttributeError: '_Union' 对象没有属性 'as_integer'
关于如何实现这一点的任何想法,或者,也许,为什么它不应该实现的理由?
我使用 python 3.6,但这并不是一成不变的,因为如果需要我可以更改版本。我使用的 IDE 是 PyCharm。
谢谢
编辑:另外两个有用的例子:
-
AnyNumber类型可以接受任何我想要的数字。也许从float和int开始,但可以扩展为支持我想要的任何类似数字的类型,例如 int-strings 或单项迭代。这种扩展立即在系统范围内,这是一个巨大的好处。例如,考虑函数
def func(n: AnyNumber):
n = AnyNumber.get_as_float()
# The rest of the function is implemented just for float.
...
- 使用
pandas,您通常可以在Series、DataFrame和Index上执行类似的操作,因此假设有一个类似于上面称为SeriesContainer的“类型类”,它简化了使用 - 允许我通过调用SeriesContainer.as_series_collection(...)或SeriesContainer.as_data_frame(...)来统一处理所有数据类型,具体取决于使用情况。
【问题讨论】:
-
你能试着用常规的打字术语来澄清你想要达到的目标吗?这些示例在构造上毫无意义。例如,
IntOrIntString之类的类型要么是 int/string 的联合,要么具有附加方法——因为 int 和 str 没有该方法。AnyNumber与 number pyramid 冲突 - 例如,复数是一个数字,但不能唯一地表示为浮点数。您是否正在寻找类型类或特征?你考虑过 ABC、singledispatch 还是第三方的 multipledispatch? -
不要迷失在细节中。如果我愿意,我可以改用
AnyNumber.get_complex或AnyNumber.get_quaternion。我也可以使用AnyRealNumber和get_float。上述示例中的所有共同点是它们的功能不是与类型匹配,而是与类型的某个方面匹配(与使用Mapping或Iterable等python 抽象不同。在所有上述情况下,我可以轻松编写代码用于数据的“标准化”形式,但以可扩展的方式支持许多其他类型。 -
正如一些答案和 cmets 正确显示的那样 - 我可以轻松地将上面给出的三个“优势”分开:我可以使用
Union[Int, String]进行静态类型检查,intStr_isinstance()用于动态类型-检查并intStr_get_number()进行标准化。然而,我的问题是将所有三个组合到同一个类中。 -
这似乎是您提出的一个非常复杂的要求。提供答案将涉及一些工作。请提供清晰的问题描述,这样人们就不会浪费时间在以后找出哪些细节是重要的,哪些不重要。重申一下,当前的要求不能始终如一地满足。例如,
a: IntOrIntString将允许a = 3(因为IntOrIntString是Union[int, str])和a.as_integer(a)(因为IntOrIntString定义as_integer)。这是错误的,因为没有(3).as_integer("12")这样的东西,例如。 -
你是正确的,因为没有
(3).as_integer()。但是,在编写代码时,它并不意味着这样使用,因为这是一个静态函数
标签: python python-3.x type-hinting python-internals