Python:从函数内部命名类型并在函数外部分配变量

问题描述 投票:1回答:1

我希望能够轻松地创建新类型,并(可选地)添加有关它们的一些信息(例如一些文档以及它们经常使用的一组变量名)。

简单的方法是:

from typing import Any, NewType, Union, List, Iterable, Optional

Key = NewType('Key', Any)
Key._aka = set(['key', 'k'])

Val = NewType('Val', Union[int, float, List[Union[int, float]]])
Val.__doc__ = "A number or list of numbers."

但是有两个原因我不喜欢这个:

  • 我必须复制粘贴我正在制作的新类型的名称的三遍(不是D.R.Y.并容易出错)

  • 我不喜欢“外部化”可选附加信息(_aka__doc__)的分配

所以我想出了这个:

from typing import Any, NewType, Union, List, Iterable, Optional

def new_type(name, tp, doc: Optional[str]=None, aka: Optional[Iterable]=None):
    """Make a new type with (optional) doc and (optional) aka, set of var names it often appears as"""
    new_tp = NewType(name, tp)
    if doc is not None: 
        setattr(new_tp, '__doc__', doc)
    if aka is not None: 
        setattr(new_tp, '_aka', set(aka))
    globals()[name] = new_tp  # is this dangerous? Does scope need to be considered more carefully?

这会给我我想要的界面:

new_type('Key', Any, aka=['key', 'k'])
new_type('Val', Union[int, float, List[Union[int, float]]], doc="A number or list of numbers.")

但是我不确定globals()[name] = new_tp这件事。如果我要在模块的顶层定义类型,这似乎是无害的,但不确定在某些边缘情况下嵌套范围的情况下如何公平。

python python-3.x python-typing
1个回答
0
投票

创建新类型的通常方法是只编写一个新类:

class Key:
    def __init__(self, key: object) -> None:
        self._key = key
        self._aka = set(['key', 'k'])

class SqlString(str):
    """A custom string which has been verified to be valid SQL."""

请注意,这种方法避免了您的DRY和范围界定问题。

[仅当您要添加任何额外的属性或文档字符串时才使用NewType -执行Foo = NewType('Foo', X)基本上与执行class Foo(X): pass相似,只是运行时开销稍有减少。

(更确切地说,类型检查器将Foo = NewType('Foo', X)像写为class Foo(X): pass一样对待,但是在运行时实际上会发生什么Foo = lambda x: x-Foo是标识函数。]


但是,由于联合不是可子类化的(根据PEP 484,这使得该NewType是非法的,因此我们确实遇到了第二个联合示例的麻烦。

相反,我个人将执行以下操作:

# A number or list of numbers
Val = Union[int, float, List[Union[int, float]]]

IMO,因为类型应该在运行时不可见,所以我认为不必麻烦附加运行时可用的文档就很有意义。

© www.soinside.com 2019 - 2024. All rights reserved.