如何在 python 中为嵌套列表和基本类型设置类型检查器?
How can I have a type checker in python for nested lists and basic types?
如果我需要为包含嵌套列表的基本类型编写类型验证器,标准方法是什么。
即如果给我一个值 a
和一个字符串 list<list<int>>
,我如何检查 a
实际上是 list
of list
of int
小号?
有 Pythonic 方法吗?
注意:我知道 Python 是关于 duck typing 的,只是在这种情况下我需要进行一些验证,因为数据将被传递到另一个系统。
您可以使用 isinstance
来检查某物的类型
def is_list_of_list_of_int(a):
return isinstance(a, list) and isinstance(a[0], list) and isinstance(a[0][0], int)
>>> is_list_of_list_of_int([[1,2,3],[2,3,4]])
True
>>> is_list_of_list_of_int(5)
False
另一种方法是 "it is better to ask forgiveness than permission"
def get_value_safe(a, i, j):
try:
return a[i][j]
except TypeError:
print('not a list of list')
return None
>>> get_value_safe([[1,2,3],[2,3,4]], 1, 2)
4
>>> get_value_safe([1,2,3], 1, 2)
not a list of list
假设您只想检查列表和基本类型,答案的第一部分是将类型规范解析为类型列表(从父到子):
import __builtin__
def parse_spec(str_spec):
return [getattr(__builtin__, x) for x in str_spec.rstrip('>').split('<')]
第二部分是验证指定值是否符合规范:
def validate(value, spec):
for t in spec:
if not isinstance(value, t):
return False
try:
value = value[0]
except TypeError:
pass
return True
因此,您可以按如下方式组合这些功能:
>>> validate([10], parse_spec('list<int>'))
True
>>> validate([10], parse_spec('int'))
False
>>> validate([['something']], parse_spec('list<list<str>>'))
True
我必须承认,这是我第一次接触递归 ages,但我认为检查对象的每一项的唯一方法是递归。或者动态规划,我不喜欢动态规划:P
我非常讨厌解析字符串,所以我选择只传递类型。
def typecheck(obj, *args):
if isinstance(obj, args[0]):
if len(args) == 1: # last one to check. Base case.
return True
if hasattr(args[0], "__iter__"):
#in other words, am I an iterator?
for i in obj:
if not typecheck(i, *args[1:]):
return False
return True
else:
return False
In [23]: typecheck([[3,3, "a"]],list, list, int)
Out[23]: False
In [24]: typecheck([[3,3]],list, list, int)
Out[24]: True
向其中添加 logging
应该很简单,因为它只是告诉您对象的确切位置是错误类型的变体
如果您想检查所有元素是否属于具有任意嵌套级别的特定类型,我会使用递归:
from collections import Iterable
def is_list_or_int(l):
if not isinstance(l, (list, int)):
return False
if isinstance(l, Iterable):
for ele in l:
if not is_list_or_int(ele):
return False
return True
输出:
In [9]: is_list_or_int([1, [2, [[["4"], 3, 4]]],2, 3, 4])
Out[9]: False
In [10]: is_list_or_int([1, [2, [[[4], 3, 4]]],2, 3, 4])
Out[10]: True
如果我需要为包含嵌套列表的基本类型编写类型验证器,标准方法是什么。
即如果给我一个值 a
和一个字符串 list<list<int>>
,我如何检查 a
实际上是 list
of list
of int
小号?
有 Pythonic 方法吗?
注意:我知道 Python 是关于 duck typing 的,只是在这种情况下我需要进行一些验证,因为数据将被传递到另一个系统。
您可以使用 isinstance
来检查某物的类型
def is_list_of_list_of_int(a):
return isinstance(a, list) and isinstance(a[0], list) and isinstance(a[0][0], int)
>>> is_list_of_list_of_int([[1,2,3],[2,3,4]])
True
>>> is_list_of_list_of_int(5)
False
另一种方法是 "it is better to ask forgiveness than permission"
def get_value_safe(a, i, j):
try:
return a[i][j]
except TypeError:
print('not a list of list')
return None
>>> get_value_safe([[1,2,3],[2,3,4]], 1, 2)
4
>>> get_value_safe([1,2,3], 1, 2)
not a list of list
假设您只想检查列表和基本类型,答案的第一部分是将类型规范解析为类型列表(从父到子):
import __builtin__
def parse_spec(str_spec):
return [getattr(__builtin__, x) for x in str_spec.rstrip('>').split('<')]
第二部分是验证指定值是否符合规范:
def validate(value, spec):
for t in spec:
if not isinstance(value, t):
return False
try:
value = value[0]
except TypeError:
pass
return True
因此,您可以按如下方式组合这些功能:
>>> validate([10], parse_spec('list<int>'))
True
>>> validate([10], parse_spec('int'))
False
>>> validate([['something']], parse_spec('list<list<str>>'))
True
我必须承认,这是我第一次接触递归 ages,但我认为检查对象的每一项的唯一方法是递归。或者动态规划,我不喜欢动态规划:P
我非常讨厌解析字符串,所以我选择只传递类型。
def typecheck(obj, *args):
if isinstance(obj, args[0]):
if len(args) == 1: # last one to check. Base case.
return True
if hasattr(args[0], "__iter__"):
#in other words, am I an iterator?
for i in obj:
if not typecheck(i, *args[1:]):
return False
return True
else:
return False
In [23]: typecheck([[3,3, "a"]],list, list, int)
Out[23]: False
In [24]: typecheck([[3,3]],list, list, int)
Out[24]: True
向其中添加 logging
应该很简单,因为它只是告诉您对象的确切位置是错误类型的变体
如果您想检查所有元素是否属于具有任意嵌套级别的特定类型,我会使用递归:
from collections import Iterable
def is_list_or_int(l):
if not isinstance(l, (list, int)):
return False
if isinstance(l, Iterable):
for ele in l:
if not is_list_or_int(ele):
return False
return True
输出:
In [9]: is_list_or_int([1, [2, [[["4"], 3, 4]]],2, 3, 4])
Out[9]: False
In [10]: is_list_or_int([1, [2, [[[4], 3, 4]]],2, 3, 4])
Out[10]: True