[英]How to implement a function to cover both single and multiple values
假設您有這樣的值:
n = 5
和一個 function 返回它的階乘,如下所示:
factorial(5)
你如何處理多個值:
nums = [1,2,3,4,5]
factorial (nums)
所以它將所有這些值的階乘作為列表返回?
在不編寫 2 種方法的情況下,最干凈的處理方法是什么? Python有處理這類情況的好辦法嗎?
def Factorial(arg):
try:
it = iter(arg)
except TypeError:
pass
else:
return [Factorial(x) for x in it]
return math.factorial(arg)
如果它是可迭代的,則遞歸應用。 否則,正常進行。
或者,您可以將最后一個return
移動到except
塊中。
如果您確定Factorial
的主體永遠不會引發TypeError
,它可以簡化為:
def Factorial(arg):
try:
return [Factorial(x) for x in arg]
except TypeError:
return math.factorial(arg)
列表理解:
[fac(n) for n in nums]
編輯:
抱歉,我誤會了,您想要一種同時處理序列和單個值的方法嗎? 我無法想象你為什么不使用兩種方法來做到這一點。
def factorial(n):
# implement factorial here
return answer
def factorial_list(nums):
return [factorial(n) for n in nums]
另一種方法是進行某種類型檢查,除非你有一些非常令人信服的理由,否則最好避免這樣做。
編輯2:
MizardX 的答案更好,投票給那個。 干杯。
有時會這樣做。
def factorial( *args ):
def fact( n ):
if n == 0: return 1
return n*fact(n-1)
return [ fact(a) for a in args ]
它提供了一個幾乎神奇的 function,它適用於簡單的值和序列。
>>> factorial(5)
[120]
>>> factorial( 5, 6, 7 )
[120, 720, 5040]
>>> factorial( *[5, 6, 7] )
[120, 720, 5040]
如果您問 Python 是否可以進行方法重載:否。 因此,執行這樣的多方法是定義方法的一種相當非 Pythonic 的方式。 此外,命名約定通常大寫 class 名稱,小寫函數/方法。
如果你想 go 無論如何,最簡單的方法就是創建一個分支:
def Factorial(arg):
if getattr(arg, '__iter__', False): # checks if arg is iterable
return [Factorial(x) for x in arg]
else:
# ...
或者,如果您喜歡,您可以制作一個裝飾器,對任何 function 執行此操作:
def autoMap(f):
def mapped(arg):
if getattr(arg, '__iter__', False):
return [mapped(x) for x in arg]
else:
return f(arg)
return mapped
@autoMap
def fact(x):
if x == 1 or x == 0:
return 1
else:
return fact(x-1) + fact(x-2)
>>> fact(3)
3
>>> fact(4)
5
>>> fact(5)
8
>>> fact(6)
13
>>> fact([3,4,5,6])
[3, 5, 8, 13]
盡管更 Pythonic 的方式是使用可變參數長度:
def autoMap2(f):
def mapped(*arg):
if len(arg) != 1:
return [f(x) for x in arg]
else:
return f(arg[0])
return mapped
@autoMap2
def fact(n):
# ...
>>> fact(3,4,5,6)
[3, 5, 8, 13]
將兩者組合成一個深度映射裝飾器:
def autoDeepMap(f):
def mapped(*args):
if len(args) != 1:
return [mapped(x) for x in args]
elif getattr(args[0], '__iter__', False):
return [mapped(x) for x in args[0]]
else:
return f(args[0])
return mapped
@autoDeepMap
def fact(n):
# ...
>>> fact(0)
1
>>> fact(0,1,2,3,4,5,6)
[1, 1, 2, 3, 5, 8, 13]
>>> fact([0,1,2,3,4,5,6])
[1, 1, 2, 3, 5, 8, 13]
>>> fact([0,1,2],[3,4,5,6])
[[1, 1, 2], [3, 5, 8, 13]]
>>> fact([0,1,2],[3,(4,5),6])
[[1, 1, 2], [3, [5, 8], 13]]
或者,如果您不喜歡列表理解語法,並且希望跳過使用新方法:
def factorial(num):
if num == 0:
return 1
elif num > 0:
return num * factorial(num - 1)
else:
raise Exception("Negative num has no factorial.")
nums = [1, 2, 3, 4, 5]
# [1, 2, 3, 4, 5]
map(factorial, nums)
# [1, 2, 6, 24, 120, 720]
您可能想看看 NumPy/SciPy 的vectorize 。
在 numpy 世界中,給定你的單整數參數階乘 function,你會做類似的事情
vFactorial=np.vectorize(Factorial)
vFactorial([1,2,3,4,5])
vFactorial(6)
盡管請注意,最后一種情況返回的是單元素 numpy 數組而不是原始 int。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.