如果第一个函数调用了第二个函数,那么第二个函数是否可以为第一个函数返回值 ?
def check_type(x):
if type(x) not in [int, float]:
return None
def square(x):
check_type(x)
return x**2
print(square(2))
>>> 4
print(square('2'))
>>> Error but should return None
我知道我可以通过使用if
then
语句来重组代码,使之成为可能,但是我想看看Python是否已内置任何东西来保存代码行。
答案 0 :(得分:5)
从概念上讲,您可能希望切换功能的顺序。您可以让square
接受check_type
作为回调,如果一切都通过,则使用经过清理的参数进行调用,而不是check_type
使用square
来检查其参数。
天真的方法可能如下:
def check_type(x, hook):
return hook(x) if type(x) in [int, float] else None
def square(x):
return x**2
print(check_type(2, square))
# 4
print(check_type('2', square))
# None
这不是超级优雅,但是它在许多方面都对您的原始方法进行了设计改进。一方面,函数square
可以自由地专注于完成其工作,而不必担心清理参数(这有助于封装)。另一方面,它使类型检查在各个函数之间更加一致,因为您可以在一个地方完成它,而不必记住在每个函数中都要做。
就优雅程度而言,python提供了一种非常干净的方法来执行此操作,称为装饰器。装饰器是一个接受函数或类作为输入并返回替换对象的函数。通常,这通常用于包装带有其他功能的功能,就像您尝试做的一样。
第一遍装饰器实现如下所示:
from functools import wraps
def check_type(func):
@wraps(f)
def wrapper(x):
return func(x) if type(x) in [int, float] else None
return wrapper
@check_type
def square(x):
return x**2
print(square(2))
# 4
print(square('2'))
# None
请注意,装饰器返回的用于替换wrapper
的{{1}}函数本身就是装饰的。 functools.wraps
通过更新名称和其他属性来修改功能对象,以使square
与原始wrapper
更加难以区分。
在不相关的注释上,我可能不允许我的函数在不适当的输入上返回值。当您返回square
时,您将迫使调用者检查None
与有效值之间的距离,从而实际上违反了首先使用类型检查器的目的。相反,例外是更好的设计选择,因为它不会降低责任:
None
最后,您可能需要重新考虑如何进行类型检查或是否完全进行类型检查。例如,您可以扩展大多数内置类。如果您想允许此类扩展名,可以使用更好的措辞
def check_type(func):
@wraps(f)
def wrapper(x):
if type(x) in [int, float]
raise TypeError ('Expected one thing but got the other')
return func(x)
return wrapper
或者您可以使用在numbers
模块中注册的抽象基类。这将使您能够处理诸如numpy标量,十进制等的内容:
if isinstance(x, (int, float)):
最后,您可能要考虑做最Python的事情,并传递支持所需操作的所有内容。这意味着根本不进行任何类型检查。如果您传递的内容实例没有if isinstance(x, numbers.Number):
方法,则解释器将在__pow__
中为您引发TypeError
。
答案 1 :(得分:4)
如果您想保存代码行(并不是说这始终是一个道德目标),则可以对以下内容使用布尔短路:
def check_type(x):
return type(x) in [int, float] or None
def square(x):
return check_type(x) and x**2
print(square(2))
# 4
print(square('2'))
# None
如果它为假,它将返回check_type(x)
的值,否则返回值square()
话虽如此,看来pythonic的方法是不进行类型检查,而是捕获错误:
def square(x):
try:
return x**2
except TypeError:
return None
这将使您的函数可以处理您可能无法预测的其他类型,但允许使用指数。例如,复数:square(2+1j)
在第一个示例中返回None
,在第二个示例中返回(3+4j)
。
答案 2 :(得分:1)
def check_type(x):
if type(x) not in [int, float]:
return None
这里的问题是,当您的类型不是int
或float
时,您将返回None
,但是当您的值处于所需类型时,它什么也不返回。
因此,实际上类型检查没有返回任何内容,并且您不能在不编写return语句的情况下从函数中返回,即,当您调用check_type
时,它返回None(来自check_type
),但是从{{1 }}功能。
马克·迈耶的答案很完美
它也应该工作-
sqauare
答案 3 :(得分:1)
check_type(x)始终向Square(x)返回None,但不让square(x)返回None。
尝试一下
def square(x):
return x**2 if isinstance(x , (int, float)) else None