3 回答
TA貢獻1829條經(jīng)驗 獲得超7個贊
在 Python 中,位置參數(shù)必須位于關(guān)鍵字參數(shù)之前——這只是該語言的規(guī)則。也就是說,有幾種方法(我不一定推薦)可以編寫一個函數(shù)來解決這個問題。
這本質(zhì)上就是內(nèi)置range函數(shù)執(zhí)行您所描述的操作的方式:
def range(*args):
# default values
start = 0
step = 1
n_args = len(args)
if not 0 < n_args < 4:
raise TypeError(f'range expected 1 arguments, got {n_args}')
elif n_args == 1:
stop = args[0]
elif n_args == 2:
start, stop = args
else:
start, stop, step = args
# etc...
它要求參數(shù)以特定順序傳遞,然后根據(jù)傳遞的參數(shù)數(shù)量確定要為哪些變量賦值。
或者,考慮以下事項:
def example(a=10, b=None):
assert b is not None, "argument 'b' is required"
# etc...
這是一個更丑陋的解決方案,因為:
您必須
b作為關(guān)鍵字參數(shù)傳遞,而不是位置參數(shù)函數(shù)簽名不會向用戶提供任何
b所需的指示 - 它看起來像是可選的,但如果未顯式傳遞,該函數(shù)將會失敗。您必須將參數(shù)的“無效”值設(shè)置為您 100% 確定沒有人愿意實際傳遞給該參數(shù)的值。
除非有真正令人信服的理由不這樣做,否則最好堅持通常的格式(首先是位置參數(shù),可選地隨后收集 leftover *args,然后是關(guān)鍵字參數(shù),可選地隨后收集 leftover **kwargs)。這是人們期望使用函數(shù)的方式,并使您的代碼更易于使用和閱讀。如果確實有令人信服的理由偏離這一點,請模仿 的設(shè)置range。
編輯:
回復(fù):您關(guān)于“更正”函數(shù)簽名以顯示某些參數(shù)名稱而不是 的問題*args,上面的示例極大地簡化了range內(nèi)置函數(shù)的工作方式。實際上,它是用 C 實現(xiàn)的,其簽名/文檔字符串在此處設(shè)置。它更類似于定義在__call__構(gòu)造函數(shù)內(nèi)運行的方法的類,而不是常規(guī)函數(shù)。
手動覆蓋對象的簽名會很棘手(更不用說避免使用“正?!眳?shù)順序的大量額外步驟)——最好將“正確”參數(shù)名稱放入文檔字符串中。
有一些非常非常古怪的方法可以做到這一點。例如,您可以將函數(shù)包裝在一個裝飾器中,該裝飾器使用類似inspect.Signature修改函數(shù)對象的東西。__init_subclass__或者,也許您可以將其轉(zhuǎn)換為一個類,讓它從某個父類繼承,然后在父類和__new__子類中使用組合來攔截和修改傳遞給構(gòu)造函數(shù)的參數(shù)。但這些解決方案還遠遠不夠,值得一問的是為什么沒有更簡單的方法來解決這個問題。在我看來,這是因為這根本不是你想做的事情。
TA貢獻1797條經(jīng)驗 獲得超6個贊
你不能。默認參數(shù)必須位于參數(shù)列表的最后。如果您想要不同的行為,那么您必須在函數(shù)內(nèi)部進行驗證。
def primes_in_interval(start=2, end=None):
assert(end is not None)
# Rest of code.
primes_in_interval(end=10)
您可以執(zhí)行類似的操作來獲取您正在尋找的調(diào)用約定。
def primes_in_interval(end_or_start, end=None):
if end is None:
start = 2
end = end_or_start
else:
start = end_or_start
end = end
# Rest of code.
primes_in_interval(10) # Start will be 2 and end 10
primes_in_interval(8, 16) # Start will be 8 and end 16
TA貢獻2041條經(jīng)驗 獲得超4個贊
你不能。range定義參數(shù)的方式是內(nèi)置range的,并且使用不同的解析參數(shù)的方式,大致相當(dāng)于接收*args, **kwargs和手動解析它們(它手動拒絕非空kwargs,但仍然必須接受它們,因為CPython 的 C API 的約定)。如果你想自己做,也可以,但 Python 沒有幫助:
def myrange(*args):
? ? if not args or len(args) > 3:
? ? ? ? raise TypeError("Expected 1-3 args")
? ? if len(args) == 1:
? ? ? ? start, step = 0, 1
? ? ? ? stop, = args
? ? else:
? ? ? ? start, stop, step = (args + (1,))[:3]? # Stupid trick to reduce number of cases
? ? # Actual work done here
添加回答
舉報
