所以我有一堆处理函数,所有这些函数都使用了(因为没有更好的词)' master'功能。这个主函数基本上是一个大的AND操作,它根据一堆布尔或字符串列的值从pandas数据帧返回相关的行(顺便说一下,数据是关于啮齿动物的行为)。
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
处理器功能准备通过相应的绘图功能绘制数据,即,性能返回(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函数添加默认值而不是完全明确的,即在所有函数中暴露init,气味,动作......,也不是完全通用的,即现在使用** 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的内部范围locals()中声明的变量组。
到目前为止我尝试了什么:
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 dict(在示例中为**默认值)。这意味着我必须在函数的内部范围内使用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
答案 0 :(得分:0)
如果你想要的只是具有不同默认参数的同一函数的不同版本的Python函数,你可以使用functools.partial
轻松创建它们,而不需要装饰器。
所以,如果你有def trial_selector(par1=..., par2=..., ...):
并且想要为各种参数设置具有不同默认设置的可调用对象,您可以这样声明它们:
导入部分
search1 = partial(trial_decorator,par1 =“ABCD”,par2 =“EFGH”) search2 = partial(trial_decorator,par1 = None,par3 =“XZY”,... 0
只需调用searchN
函数,只需要关心新函数
您想要再次覆盖的参数或参数。
现在,如果您需要其他功能的装饰器,那么您的代码还有一些额外的评论:
您可能不知道的是,如果您使用**kwargs
来调用函数,则函数签名本身不需要使用kwargs。
因此,对于你的内部函数,你可以拥有一个完整的explict参数列表(比如你的第一个listng -
,而不是仅仅def example_func(*args, **kwargs):
作为签名。
def trial_selector(session,
init='NSWE', odor='ABCD', action='LRFB',
action_choice='LRFB', goal='NSWE', qNa='both',
cl=False, invalid=False):
仍然用一个将kwargs传递给它的装饰器包装它,正如你在“我尝试过的”代码中所做的那样。而且,在你的示例装饰器上,你已经重新创建了一个相当复杂的字典“更新”方法 - 它可以写成:
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',
...
'invalid': False}
defaults.update(kwargs)
return func(*args, **defaults)
return wrapper
如果这就是你想要的,那就是你需要的一切。此外,装饰器语法是有帮助的 - 在这种情况下,看起来您可以使用其中几个“默认args”装饰器而不使用装饰器语法 - 您可以像下面这样编写它:
def full_search_function(all, default, parameters, ...):
...
def decorator_for_type1_search(...):
...
type1_search = decorator_for_type1_search(full_Search_function)
此时您将type1_search
作为函数添加decorator_for_type1_search
中的参数 - 您可以根据需要创建尽可能多的参数。