所以我有一堆處理函數,並且它們都使用(缺少更好的單詞)'主'功能。這個主函數基本上是一個很大的AND操作,根據一堆布爾值或字符串列的值(數據是關於齧齒動物的行爲)從熊貓數據框返回相關行。如何使用裝飾器添加任意kwargs和默認功能
def trial_selector(session,
init='NSWE', odor='ABCD', action='LRFB',
action_choice='LRFB', goal='NSWE', qNa='both',
cl=False, invalid=False):
trials = load_trials(session) # Wrapper load func that is somwhere else
# input checks transform str in lists... ugly but needed for now
if type(init) == str:
init = [init] if len(init) == 1 else [x for x in init]
if type(odor) == str:
odor = [odor] if len(odor) == 1 else [x for x in odor]
mapping = {'A': 1, 'B': 2, 'C': 3, 'D': 4}
odor = [mapping[x] for x in odor]
if type(action) == str:
action = [action] if len(action) == 1 else [x for x in action]
if type(action_choice) == str:
action_choice = [action_choice] if len(action_choice) == 1 else [x for x in action_choice]
if type(goal) == str:
goal = [goal] if len(goal) == 1 else [x for x in goal]
# init odor action action_choice goal selection
tr = trials[trials.init.isin(init) & trials.valve_number.isin(odor)
& trials.action.isin(action)
& trials.action_choice.isin(action_choice)
& trials.goal_choice.isin(goal)]
# TODO: Invalid, correction loop and trial type (not complete)
if not invalid:
tr = tr[tr.valid]
if not cl:
tr = tr[~tr.correction_loop]
if qNa == 'both':
tr = tr
elif qNa == 'q':
tr = tr[~tr.solution]
elif qNa == 'a':
tr = tr[tr.solution]
return tr
處理器功能準備的數據,以通過相應的繪圖功能被繪製,即tperformance返回(X,Y,yerr)及其使用tplot_performance。
# tsargs are the arguments of the trial_selector function
def tperformance_uni(sessionName, **tsargs):
trials = trial_selector(sessionName, **tsargs)
x = trials.correct.dropna().index
y = trials.correct.dropna().values
return (x, y)
@check_session
def tperformance(sessionList, smooth=False, **tsargs):
temp = []
out = pd.DataFrame()
for session in sessionList:
x, y = tperformance_uni(session, **tsargs)
temp.append(pd.Series(y, index=x, name=session))
out = pd.concat(temp, axis=1,)
x = out.mean(axis=1).index
y = out.mean(axis=1).values
yerr = out.std(axis=1)/np.sqrt(len(out.columns))
yerr[yerr.isnull()] = 0
if not smooth or type(smooth) is bool:
win = win_size(x)
else:
win = win_size(x, default=smooth)
ysmooth = sm(y, win)
yerrsmooth = sm(yerr, win)
if len(x) != len(ysmooth):
ysmooth = ysmooth[1:]
if len(x) != len(yerrsmooth):
yerrsmooth = yerrsmooth[1:]
return (x, y, yerr) if not smooth else (x, ysmooth, yerrsmooth)
而繪圖的功能,例如是:
def tplot_performance(sessionName, ax=False, decor=False, err=False,
c='b', ls='-', m='',
smooth=False,
**tsargs):
"""
Plots correct across trials
"""
if not ax:
ax = plt.subplot2grid((1, 1), (0, 0), rowspan=1, colspan=1)
# ---
x, y, yerr = tperformance(sessionName, smooth=smooth, **tsargs)
# ---
ax.plot(x, y, ls=ls, marker=m, color=c, linewidth=2)
if err:
ax.fill_between(x, y-yerr, y+yerr, color='gray', alpha=0.25)
if decor:
tplot_performance_template(sessionName, ax=ax)
return (x, y, yerr)
我設法成功地實現使用的裝飾,基本上保證了會議的參數檢查@check_session是字符串列表。
def check_session(func):
"""Ensures session is of type list, if string will make list of one value
"""
def wrapper(session, **kwargs):
session = [session] if type(session) is str else session
return func(session, **kwargs)
return wrapper
到目前爲止好。 現在,我想添加trial_selector函數的默認值,而不是完全明確的,即在所有函數中暴露初始化,異常,動作......,也不是完全通用的,即現在使用** tsargs的方式。
基本上我想使用像@tsargs_defaults這樣的裝飾器,這樣我就可以在處理函數中使用默認值來做東西。我可以有輸入參數模塊,讓我來聲明是這樣的:
@defalut_bla
@tsargs_defaults
def example_func(*args, **kwargs):
if init == 'N':
do something
if var_in_defalut_bla == someVal:
do something else
的裝飾應該添加的那些在FUNC的範圍內當地人()聲明的變量組。
我試過到目前爲止:
def tsargs_defaults(func):
"""Adds trial_selector arguments and their defaults to function
tsargs = init='NSWE', odor='ABCD', action='LRFB', action_choice='LRFB',
goal='NSWE', qNa='both', cl=False, invalid=False,
"""
def wrapper(*args, **kwargs):
defaults = {'init': 'NSWE',
'odor': 'ABCD',
'action': 'LRFB',
'action_choice': 'LRFB',
'goal': 'NSWE',
'qNa': 'both',
'cl': False,
'invalid': False}
for k in kwargs:
if k in defaults:
defaults[k] = kwargs[k]
elif k not in defaults:
defaults.update({k: kwargs[k]})
return func(*args, **defaults)
return wrapper
然而,這會增加我想要的不是局部範圍內,但爲kwargs字典(**在本例中的默認值)。這意味着我必須在函數的內部範圍內使用kwargs['init'] == 'N'
而不是init == 'N'
。
據我所知,這是一個非問題的巨大解釋,因爲這類代碼的工作類型,但我有一堆處理和繪圖功能,使用暴露的默認參數做不同的事情,並希望避免重構所有的。 也許有沒有辦法,或者我的問題是病態提出記住它的第一次嘗試使用Python裝飾器。無論如何我想多瞭解一點。 任何幫助表示讚賞! 感謝
BTW:我使用python 3.4
TL; DR
# some_kwargs {'one': 1, 'two': 2}
# some_other_kwargs {'three': 3, 'four': 4}
@some_other_kwargs
@some_kwargs
def example_func(*args, **kwargs):
print(one, two, three, four) # does not work
print(kwargs['one'], kwargs['two'], kwargs['three'], kwargs['four']) # works
這不是*完全清楚,但你是否在尋找'kwargs.get(鍵,默認[鍵])'?你能把這個簡化爲一個簡單的例子嗎? – jonrsharpe
倒數第二個代碼塊是一個簡單的例子,其中kwarg _init_從* @ tsargs_defaults *裝飾器添加到內部作用域,而_var_in_default_bla_由* @ default_bla *裝飾器添加。現在我可以檢查init =='N'的唯一方法是使用'if kwargs ['init'] =='N'' – nico
否;如果你使用任意'kwargs',你必須從字典中獲得它們(除非你像更新'locals'那樣做一些hacky)。還要注意,你應該使用'isinstance'而不是'type'。 – jonrsharpe