您使用的语法似乎不太可能符合PEP 484定义的类型提示。
部分原因是PPE从未声明允许使用任意表达式作为类型提示,部分原因是我不认为您的示例确实符合PEP 484试图实现的精神。
特别是,Python类型化生态系统的一个重要设计目标是在“运行时世界”和“静态类型”世界之间保持相当严格的划分。特别是,应该始终可以在运行时完全忽略类型提示,但是如果在评估时类型提示有时会产生副作用,这将是不可能的。
有人最终会设计出允许您尝试做的PEP,并成功地为它的接受辩护,但这并非不可能,但我认为没有人在从事这种PEP的工作,或者是否有很大的需求
附加或记录元数据的更规范的方法可能是通过执行以下操作来明确显示副作用操作:
# Alternatively,make this a descriptor class if you want to do
# even fancier things: https://docs.python.org/3/howto/descriptor.html
def magic() -> Any:
# magic here
class Foo:
value: int = magic()
def __init__(self,value):
self.value = value
...或使用表面上刚被接受的PEP 593中描述的新Annotated
类型,它允许类型提示和任意非类型提示信息共存:
# Note: it should eventually be possible to import directly from 'typing' in
# future versions of Python,but for now you'll need to pip-install
# typing_extensions,the 'typing' backport.
from typing_extensions import Annotated
def magic():
# magic here
class Foo:
value: Annotated[int,magic()]
def __init__(self,value):
self.value = value
最后一种方法的主要警告是,鉴于Pycharm非常新,我不认为Pycharm还支持Annotated
类型提示。
将所有这些放在一边,值得注意的是,拒绝PEP 484并继续使用Pycharm碰巧理解的内容并不一定错误。 Pycharm显然可以理解您的示例(也许这是Pycharm如何实现类型分析的实现工件),这让我感到有些困惑,但是,如果它对您有用,并且如果将您的代码库调整为符合PEP 484标准,那将非常痛苦。随便摆放什么都是合理的。
如果您仍然希望让使用 的其他开发人员使用PEP 484类型提示来使用您的代码,则可以始终决定将pyi stub文件与软件包一起分发,如PEP 561。
生成这些存根文件将花费大量工作,但是存根确实提供了一种方法,使选择退出使用PEP 484的代码与尚未使用PEP 484的代码互操作。
,
以下内容可能会满足您的要求;我不确定。基本上,将存在函数test
,这样,除非用户obj.memvar = y
返回test(y)
,否则用户每次写True
都会引发错误。例如,foo
可以测试y
是否是int
类的实例。
import typing
import io
import inspect
import string
class TypedInstanceVar:
def __init__(self,name:str,test:typing.Callable[[object],bool]):
self._name = name
self._test = test
def __get__(descriptor,instance,klass):
if not instance:
with io.StringIO() as ss:
print(
"Not a class variable",file=ss
)
msg = ss.getvalue()
raise ValueError(msg)
return getattr(instance,"_" + descriptor._name)
@classmethod
def describe_test(TypedInstanceVar,bool]):
try:
desc = inspect.getsource(test)
except BaseException:
try:
desc = test.__name__
except AttributeError:
desc = "No description available"
return desc.strip()
@classmethod
def pretty_string_bad_input(TypedInstanceVar,bad_input):
try:
input_repr = repr(bad_input)
except BaseException:
input_repr = object.__repr__(bad_input)
lamby = lambda ch:\
ch if ch in string.printable.replace(string.whitespace,"") else " "
with io.StringIO() as ss:
print(
type(bad_input),''.join(map(lamby,input_repr))[0:20],file=ss,end=""
)
msg = ss.getvalue()
return msg
def __set__(descriptor,new_val):
if not descriptor._test(new_val):
with io.StringIO() as ss:
print(
"Input " + descriptor.pretty_string_bad_input(new_val),"fails to meet requirements:",descriptor.describe_test(descriptor._test),sep="\n",file=ss
)
msg = ss.getvalue()
raise TypeError(msg)
setattr(instance,"_" + descriptor._name,new_val)
下面,我们看到TypedInstanceVar
在使用中:
class Klass:
x = TypedInstanceVar("x",lambda obj: isinstance(obj,int))
def __init__(self,x):
self.x = x
def set_x(self,x):
self.x = x
#######################################################################
try:
instance = Klass(3.4322233)
except TypeError as exc:
print(type(exc),exc)
instance = Klass(99)
print(instance.x) # prints 99
instance.set_x(44) # no error
print(instance.x) # prints 44
try:
instance.set_x(6.574523)
except TypeError as exc:
print(type(exc),exc)
第二个例子:
def silly_requirement(x):
status = type(x) in (float,int)
status = status or len(str(x)) > 52
status = status or hasattr(x,"__next__")
return status
class Kalzam:
memvar = TypedInstanceVar("memvar",silly_requirement)
def __init__(self,memvar):
self.memvar = memvar
instance = Kalzam("hello world")
第二个示例的输出是:
TypeError: Input <class 'str'> 'hello world'
fails to meet requirements:
def silly_requirement(x):
status = type(x) in (float,"__next__")
return status
本文链接:https://www.f2er.com/3131436.html