python:自动区分list/tuple/array和int/float
python: automatically differentiate between list / tuple / array and int / float
我有一些对象可以是浮点数(或整数)或元组(或列表或数组)。是否可以使用惯用的 Python 来避免编写 if
/elif
函数?现在我有
def f(attribute_a,attribute_b):
if type(attribute_a) == float or type(attribute_a) == int:
result = attribute_a + attribute_b
elif type(attribute_a) == list or type(attribute_a) == tuple or type(attribute_a) == array:
result = numpy.array([ attribute_a[i] + attribute_b[i] for i in range(len(attribute_a)) ])
return result
我想避免 elif 的东西,因为有时我希望 attribute_a 是一个浮点数,但 attribute_b 是一个列表,在这种情况下,我想要像
result = numpy.array([ attribute_a + attribute_b[i] for i in range(len(attribute_b)) ])
因为我有五个不同的属性,所以不可能为每个可能的组合写出完整的 if
循环集,其中一个是数字,哪个是列表。
感谢任何帮助,
谢谢,
山姆
编辑,15 年 1 月 23 日: 一种想法是定义两个新函数如下
def general_value(x,i):
if type(x)==float or type(x)==int:
return x
elif type(x)==list or type(x)==tuple:
return x[i]
def general_len(x):
if type(x)==float or type(x)==int:
return 1
elif type(x)==list or type(x)==tuple:
return len(x)
(或对 isintance 等的各种概括),然后将它们插入到需要的地方。这是一个合理的黑客攻击,还是某种程度上不恰当?
使用 isinstance 可以传递类型元组以避免多重 or's
:
if isinstance(attribute_a,(int,float))
...
elif isinstance(attribute_a,(list,tuple, array)):
如果您只能有两种可能的情况,请使用 if/else:
if isinstance(attribute_a,(int,float))
result = ...
else:
result = ...
您可以使用条件表达式,但您的语句会相当长:
result = attribute_a + attribute_b if isinstance(attribute_a,(int,float)) else numpy.array([ attribute_a[i] + attribute_b[i] for i in range(len(attribute_a)) ])
如果要检查一组可能匹配组合的两个属性:
if isinstance(attribute_a,(list,tuple,float) and isinstance(attribute_b,(float,list))):
另一种方法是存储isinstance的结果并否定检查以避免重复调用:
a,b = if isinstance(attribute_a,(list,tuple) ,isinstance(attribute_b,float))
if a and b:
...
elif a and not b:
...
else:
....
如果你想检查是否是元组、列表等,那么你可以使用:
from collections import Iterable
def check(ele):
return isinstance(ele,Iterable) and not isinstance(ele,basestring)
然后:
if check(attribute_a) and check(attribute_b):
.....
您可能要考虑使用抽象基 class 来减少组合的数量。
已经有一个 abc 来测试你的参数之一是 int
还是 float
;它是 numbers.Real
:
assert isinstance(1,numbers.Real)
assert isinstance(1.1,numbers.Real)
也已经有一个 abc 来测试你的参数之一是 list
、tuple
还是 array
。是 collections.abc.Container
:
assert isinstance((1,),collections.abc.Container)
assert isinstance([],collections.abc.Container)
assert isinstance(array([]),collections.abc.Container)
所以函数变为:
def f(attribute_a,attribute_b):
if isinstance(attribute_a,numbers.Real) and isinstance(attribute_b,numbers.Real):
#Both arguments are Real numbers
result = attribute_a + attribute_b
elif isinstance(attribute_a,collections.abc.Container) and isinstance(attribute_b,collections.abc.Container):
#Both arguments are Containers
result = numpy.array([ attribute_a[i] + attribute_b[i] for i in range(len(attribute_a)) ])
elif isinstance(attribute_a,numbers.Real) and isinstance(attribute_b,collections.abc.Container):
# First argument is a Real number, second is a Container
result = numpy.array([ attribute_a + attribute_b[i] for i in range(len(attribute_b)) ])
elif isinstance(attribute_a,collections.abc.Container) and isinstance(attribute_b,numbers.Real):
# First argument is a Container, second is a Real number
result = numpy.array([ attribute_a[i] + attribute_b for i in range(len(attribute_a)) ])
return result
使用抽象基数 classes 而不是 中的 isinstance(var,(list, tuple, array))
有一个重要的潜在优势:检查 abc 将允许您的代码工作甚至"act like" 这些容器的类型,但不一定是它们的子class。对于 class 也是如此 "act like" 和 Real
但不一定是 int
或 float
的子class。根据您的用例,这也可能是一个缺点(例如,请参见下面关于 str
对象的注释)。
编辑:下面评论中的重要问题是:
assert isinstance("some string",collections.abc.Container)
如果从可迭代类型中限制字符串很重要(看起来可能很重要),可以创建自定义抽象基础 class using the abc
module.
或者,您可以只添加 and not isinstance(var,str)
(仅 Python 3)。
编辑:不幸的是,此答案的 overload
部分不适用于 OP,因为他 <3.0,但也许它会对其他人有所帮助。
这个问题也让我想起了overload
library,一直想试试。
使用该模块,尝试使用抽象基础 classes 来解决您的问题:
from overload import overload
from collections.abc import Container
from numbers import Real
@overload
def f(attribute_a:Container,attribute_b:Container):
'''Both arguments are Containers, e.g. list, tuple, or array'''
return numpy.array([ attribute_a[i] + attribute_b[i] for i in range(len(attribute_a)) ])
@f.add
def f(attribute_a:Real,attribute_b:Real):
'''Both arguments are Real numbers, e.g. int, float'''
attribute_a + attribute_b
@f.add
def f(attribute_a:Real,attribute_b:Container):
'''First argument is a Real number, second is a Container'''
return numpy.array([ attribute_a + attribute_b[i] for i in range(len(attribute_b)) ])
@f.add
def f(attribute_a:Container,attribute_b:Real):
'''First argument is a Container, second is a Real number'''
return f(attribute_b,attribute_a)
我有一些对象可以是浮点数(或整数)或元组(或列表或数组)。是否可以使用惯用的 Python 来避免编写 if
/elif
函数?现在我有
def f(attribute_a,attribute_b):
if type(attribute_a) == float or type(attribute_a) == int:
result = attribute_a + attribute_b
elif type(attribute_a) == list or type(attribute_a) == tuple or type(attribute_a) == array:
result = numpy.array([ attribute_a[i] + attribute_b[i] for i in range(len(attribute_a)) ])
return result
我想避免 elif 的东西,因为有时我希望 attribute_a 是一个浮点数,但 attribute_b 是一个列表,在这种情况下,我想要像
result = numpy.array([ attribute_a + attribute_b[i] for i in range(len(attribute_b)) ])
因为我有五个不同的属性,所以不可能为每个可能的组合写出完整的 if
循环集,其中一个是数字,哪个是列表。
感谢任何帮助, 谢谢, 山姆
编辑,15 年 1 月 23 日: 一种想法是定义两个新函数如下
def general_value(x,i):
if type(x)==float or type(x)==int:
return x
elif type(x)==list or type(x)==tuple:
return x[i]
def general_len(x):
if type(x)==float or type(x)==int:
return 1
elif type(x)==list or type(x)==tuple:
return len(x)
(或对 isintance 等的各种概括),然后将它们插入到需要的地方。这是一个合理的黑客攻击,还是某种程度上不恰当?
使用 isinstance 可以传递类型元组以避免多重 or's
:
if isinstance(attribute_a,(int,float))
...
elif isinstance(attribute_a,(list,tuple, array)):
如果您只能有两种可能的情况,请使用 if/else:
if isinstance(attribute_a,(int,float))
result = ...
else:
result = ...
您可以使用条件表达式,但您的语句会相当长:
result = attribute_a + attribute_b if isinstance(attribute_a,(int,float)) else numpy.array([ attribute_a[i] + attribute_b[i] for i in range(len(attribute_a)) ])
如果要检查一组可能匹配组合的两个属性:
if isinstance(attribute_a,(list,tuple,float) and isinstance(attribute_b,(float,list))):
另一种方法是存储isinstance的结果并否定检查以避免重复调用:
a,b = if isinstance(attribute_a,(list,tuple) ,isinstance(attribute_b,float))
if a and b:
...
elif a and not b:
...
else:
....
如果你想检查是否是元组、列表等,那么你可以使用:
from collections import Iterable
def check(ele):
return isinstance(ele,Iterable) and not isinstance(ele,basestring)
然后:
if check(attribute_a) and check(attribute_b):
.....
您可能要考虑使用抽象基 class 来减少组合的数量。
已经有一个 abc 来测试你的参数之一是 int
还是 float
;它是 numbers.Real
:
assert isinstance(1,numbers.Real)
assert isinstance(1.1,numbers.Real)
也已经有一个 abc 来测试你的参数之一是 list
、tuple
还是 array
。是 collections.abc.Container
:
assert isinstance((1,),collections.abc.Container)
assert isinstance([],collections.abc.Container)
assert isinstance(array([]),collections.abc.Container)
所以函数变为:
def f(attribute_a,attribute_b):
if isinstance(attribute_a,numbers.Real) and isinstance(attribute_b,numbers.Real):
#Both arguments are Real numbers
result = attribute_a + attribute_b
elif isinstance(attribute_a,collections.abc.Container) and isinstance(attribute_b,collections.abc.Container):
#Both arguments are Containers
result = numpy.array([ attribute_a[i] + attribute_b[i] for i in range(len(attribute_a)) ])
elif isinstance(attribute_a,numbers.Real) and isinstance(attribute_b,collections.abc.Container):
# First argument is a Real number, second is a Container
result = numpy.array([ attribute_a + attribute_b[i] for i in range(len(attribute_b)) ])
elif isinstance(attribute_a,collections.abc.Container) and isinstance(attribute_b,numbers.Real):
# First argument is a Container, second is a Real number
result = numpy.array([ attribute_a[i] + attribute_b for i in range(len(attribute_a)) ])
return result
使用抽象基数 classes 而不是 isinstance(var,(list, tuple, array))
有一个重要的潜在优势:检查 abc 将允许您的代码工作甚至"act like" 这些容器的类型,但不一定是它们的子class。对于 class 也是如此 "act like" 和 Real
但不一定是 int
或 float
的子class。根据您的用例,这也可能是一个缺点(例如,请参见下面关于 str
对象的注释)。
编辑:下面评论中的重要问题是:
assert isinstance("some string",collections.abc.Container)
如果从可迭代类型中限制字符串很重要(看起来可能很重要),可以创建自定义抽象基础 class using the abc
module.
或者,您可以只添加 and not isinstance(var,str)
(仅 Python 3)。
编辑:不幸的是,此答案的 overload
部分不适用于 OP,因为他 <3.0,但也许它会对其他人有所帮助。
这个问题也让我想起了overload
library,一直想试试。
使用该模块,尝试使用抽象基础 classes 来解决您的问题:
from overload import overload
from collections.abc import Container
from numbers import Real
@overload
def f(attribute_a:Container,attribute_b:Container):
'''Both arguments are Containers, e.g. list, tuple, or array'''
return numpy.array([ attribute_a[i] + attribute_b[i] for i in range(len(attribute_a)) ])
@f.add
def f(attribute_a:Real,attribute_b:Real):
'''Both arguments are Real numbers, e.g. int, float'''
attribute_a + attribute_b
@f.add
def f(attribute_a:Real,attribute_b:Container):
'''First argument is a Real number, second is a Container'''
return numpy.array([ attribute_a + attribute_b[i] for i in range(len(attribute_b)) ])
@f.add
def f(attribute_a:Container,attribute_b:Real):
'''First argument is a Container, second is a Real number'''
return f(attribute_b,attribute_a)