python - 约束可能值的 Python 类型提示友好类型
问题描述
我想要一种 python 类型提示友好的方式来创建具有受限值范围的类型。
例如,基于类型的URLstr
类型只接受看起来像“http”URL 的字符串。
# this code is made up and will not compile
class URL(typing.NewType('_URL', str)):
def __init__(self, value: str, *args, **kwargs):
if not (value.startswith('http://') or value.startswith('https://')):
raise ValueError('string is not an acceptable URL')
解决方案
覆盖内置的不可变类型效果很好
压倒一切str
;http URL 字符串
这是一个覆盖的示例str
。这不需要typing
模块,但仍然适用于类型提示。
这个str
派生类断言初始化的字符串看起来像一个 http URL 字符串。
class URL(str):
def __new__(cls, *value):
if value:
v0 = value[0]
if not type(v0) is str:
raise TypeError('Unexpected type for URL: "%s"' % type(v0))
if not (v0.startswith('http://') or v0.startswith('https://')):
raise ValueError('Passed string value "%s" is not an'
' "http*://" URL' % (v0,))
# else allow None to be passed. This allows an "empty" URL instance, e.g. `URL()`
# `URL()` evaluates False
return str.__new__(cls, *value)
这导致一个类只允许一些字符串。否则,它的行为就像一个不可变的str
实例。
# these are okay
URL()
URL('http://example.com')
URL('https://example.com')
URL('https://')
# these raise ValueError
URL('example') # ValueError: Passed string value "example" is not an "http*://" URL
URL('') # ValueError: Passed string value "" is not an "http*://" URL
# these evaluate as you would expect
for url in (URL(), # 'False'
URL('https://'), # 'True'
URL('https://example.com'), # 'True'
):
print('True') if url else print('False')
(更新:后来我找到了purl Python 库)
另一个例子,
压倒一切int
;约束整数范围Number
这个int
派生类只允许1
通过9
包容的值。
这也有一个特殊的功能。如果一个实例被初始化为空(Number()
),那么该值等于0
(这个行为是从int
类派生的)。在这种情况下,__str__
应该是'.'
(程序要求)。
class Number(int):
"""integer type with constraints; part of a Sudoku game"""
MIN = 1 # minimum
MAX = 9 # maximum
def __new__(cls, *value):
if value:
v0 = int(value[0])
if not (cls.MIN <= v0 <= cls.MAX):
raise ValueError('Bad value "%s" is not acceptable in'
' Sudoku' % (v0,))
# else:
# allow None to be passed. This allows an "empty" Number instance that
# evaluates False, e.g. `Number()`
return int.__new__(cls, *value)
def __str__(self):
"""print the Number accounting for an "empty" value"""
if self == 0:
return '.'
return int.__str__(self)
这样可以确保尽早处理错误的输入。否则,它的行为就像一个int
.
# these are okay
Number(1)
Number(9)
Number('9')
# this will evaluate True, just like an int
Number(9) == int(9)
Number('9') == int(9)
Number('9') == float(9)
# this is okay, it will evaluate False
Number()
print('True') if Number() else print('False') # 'False'
# these raise ValueError
Number(0) # ValueError: Bad value "0" is not acceptable in Sudoku
Number(11) # ValueError: Bad value "11" is not acceptable in Sudoku
Number('11') # ValueError: Bad value "11" is not acceptable in Sudoku
以及特殊的“功能”
print(Number(1)) # '1' (expected)
print(Number()) # '.' (special feature)
继承不可变类型的技术源自此 SO answer。
推荐阅读
- r - R中的多行到一行
- dart - 如何从飞镖中的变量列表中获取值
- machine-learning - 使用供应测试集进行预测的错误是什么
- c# - Xamarin 窗体选定的选项卡顶部边框
- javascript - 循环遍历对象对象的简写
- c++ - 获取特征 MatrixXf 中的每一行
- javascript - mapbox GL js中线串周围的可点击区域
- amazon-web-services - startjobrun 和 getjobrun- StepFunction with Glue 有什么区别?
- hyperledger-fabric - 如何在 Hyperledger 结构链码中处理外部数据库
- c# - 对象引用未设置为对象的实例。对象引用未设置为对象的实例