这似乎不起作用:
from typing import NewType
MyStr = NewType("MyStr", str)
x = MyStr("Hello World")
isinstance(x, MyStr)
我什至没有得到
False
,但是TypeError: isinstance() arg 2 must be a type or tuple of types
,因为MyStr
是一个函数,而isinstance
想要一个或多个type
。
即使
assert type(x) == MyStr
或 is MyStr
也会失败。
我做错了什么?
交叉引用: 从 str 或 int 继承
同一问题更详细:https://stackoverflow.com/a/2673802/1091677
如果您想子类化 Python 的
str
,您需要执行以下操作:
class MyStr(str):
# Class instances construction in Python follows this two-step call:
# First __new__, which allocates the immutable structure,
# Then __init__, to set up the mutable part.
# Since str in python is immutable, it has no __init__ method.
# All data for str must be set at __new__ execution, so instead
# of overriding __init__, we override __new__:
def __new__(cls, *args, **kwargs):
return str.__new__(cls, *args, **kwargs)
然后:
x = MyStr("Hello World")
isinstance(x, MyStr)
按预期返回
True
与 python 3.10 一样...
我推测答案是 “为什么 Python NewType 与 isinstance 和 type 不兼容?” ...是“这是 NewType 的限制”。
我推测答案是 “我究竟做错了什么?” ... 没什么”。您假设 NewType 创建一个新的运行时类型,但事实似乎并非如此。
不管它的价值如何,我希望它能起作用。
也许您想要一个类似于 str 的方法但不是 str 的类型?
获得这种效果的一个简单方法就是:
class MyStr:
value:str
def __init__(self,value:str):
self.value=value
pass
...但这意味着使用所有字符串方法都是“手动”的,例如
x=MyStr('fred')
x.value.startswith('fr')
...您可以使用@dataclass 添加比较等。
这不是一个一刀切的答案,但它可能适合您的应用。
那就简单点吧
class MyStr:
value:str
def __init__(self,value:str):
self.value=value
...像 Str 一样通用(不完整)https://github.com/urnest/urnest/blob/master/xju/newtype.py
...你可以写:
class MyStrType:pass; class MyOtherStrType:pass
class MyStr(Str[MyStrType]):
pass
class MyOtherStr(Str[MyOtherStrType]):
pass
x=MyStr('fred')
y=MyOtherStr('fred')
x < y # ! mypy error distinct types MyStr and MyOtherStr
这就是我所追求的,这可能也是你所追求的?我必须单独提供 Int、Str,但根据我的经验,不同的 int、str、float、bool、bytes 类型提供了很多可读性和错误拒绝杠杆。我很快就会将 Float、Bool、Bytes 添加到 xju.newtype 中,并为它们提供所有全套方法。
在 python 3.10 中,外观可能已被“修复”:
https://docs.python.org/3/library/typing.html?highlight=typing#newtype
说:
3.10 版本中的更改:NewType 现在是一个类而不是一个函数。通过常规函数调用 NewType 时会产生一些额外的运行时成本。不过,这个成本将在 3.11.0 中降低。
当我写这篇文章来尝试你的例子时,我手头没有 3.10。