我有一个带有许多输入参数的函数,我需要一个函数来为每个参数返回一个参数名称列表(而不是值),这些参数的值为''或无
通常我会在这种方法中抛出异常。如果有人想通过抛出异常来解决问题,那很好。我仍然要求函数返回参数名列表。
总结
提出问题的答案:
if not foo:
在函数之间变得繁琐,我们有很多函数。请解释“”“我们平台的性质”“”。还“”“它到达个别变量”“”...个别变量在什么名称空间?什么“”“(预处理)”“”是什么意思? - John Machin 2天前。答案:变量位于全局命名空间中。我们使用代码注入(类似于C预处理器如何用代码代替宏名,除了我们用变量值替换标签,类似于:
DATABASE_NAME = ^ - ^将用户为数据库名称输入的变量放在此处^ - ^
在预处理器运行后以此结束:
DATABASE_NAME = "DB1"
这是一个具体示例,说明为什么抛出异常的简单方法不起作用。我已经重写了使用异常而不是通过请求返回值:
def validate_parameters(params_map):
"""
map is like {foo: "this is foo"}
"""
missing_params_info = []
for k,v in params_map.items():
if not k:
missing_params_info.append(v)
if missing_params_info:
raise TypeError('These parameters were unset: %s' % missing_params_info)
params = {}
params['foo'] = '1'
params['bar'] = '2'
params['empty'] = ''
params['empty2'] = ''
params['None'] = None
params_map = {
params['foo']: 'this is foo',
params['bar']: 'this is bar',
params['empty']: 'this is empty',
params['empty2']: 'this is empty2',
params['None']: 'this is None',
}
print validate_parameters(params_map)
bash-3.00# python /var/tmp/ck.py
Traceback (most recent call last):
File "/var/tmp/ck.py", line 26, in ?
print validate_parameters(params_map)
File "/var/tmp/ck.py", line 10, in validate_parameters
raise TypeError('These parameters were unset: %s' % missing_params_info)
TypeError: These parameters were unset: ['this is empty2', 'this is None']
它对我们不起作用的两个原因:它只打印empty2,即使有另一个空参数“空”。 “empty”被“empty2”覆盖,因为它们在地图中使用相同的键。
第二个原因:我需要在运行此函数后的某个时刻将描述列表添加到变量中。也许这有可能是例外,但我现在不知道如何。
我发布的答案似乎解决了所有这些问题,但并不理想。我标记了问题的答案,但如果有人发布了更好的答案,我会改变这个问题。
谢谢!
答案 0 :(得分:2)
我很确定我不理解这个问题,或者您发布的“最佳解决方案”如何符合要求,但仅仅是从以下方面开始:
我有一个带有许多输入参数的函数,我需要一个函数 这将返回每个参数名称列表(而不是值) 值为''或无
的参数
这是一个简单的方法来做这条线似乎要求:
def validate_parameters(args):
unset = []
for k in args:
if args[k] is None or args[k]=="":
unset.append(k)
return unset
然后只需从函数的第一行行调用validate_parameters:
def foo(a, b, c):
print "Unset:", validate_parameters(locals())
>>> foo(1, None, 3)
Unset: ['b']
>>> foo(1, None, "")
Unset: ['c', 'b']
如果不是Python 2.2的要求,你可以在单行列表理解中完成所有操作。重要的是你必须从函数的第一行调用它,以确保locals()
只获取参数而不是任何其他局部变量。
答案 1 :(得分:1)
为什么不 Zoidberg 装饰者?
def argsnotempty(**requiredargs):
def decorator(func):
def wrapper(*args, **kwargs):
code = func.func_code
argsreq = code.co_argcount - 1
argsrec = len(args)
posargs = code.co_varnames[1:argsreq + 1]
errs = []
# validate positional args
for i, arg in enumerate(args):
if i == len(posargs):
break
# falsy but not False: 0, '', None, [], etc.
if not (arg or arg is False):
argname = posargs[i]
if argname in requiredargs:
errs.append(argname + " (" + requiredargs[argname] + ")")
# validate keyword args
for argname, arg in kwargs.iteritems():
if argname in requiredargs:
if not (arg or arg is False):
errs.append(argname + " (" + requiredargs[argname] + ")")
# make sure all required args are present
for argname in requiredargs:
if argname not in kwargs and argname not in posargs:
errs.append(argname + " (" + requiredargs[argname] + ")")
return func(errs, *args, **kwargs)
wrapper.__name__, wrapper.__doc__ = func.__name__, func.__doc__
return wrapper
return decorator
装饰器检查以确保指定的参数不为空,然后使用" friendly"的列表调用包装函数。参数名称为空白作为第一个参数。它还尝试检查关键字参数。没有为装饰者指定的参数也不会被检查。
用法:
@argsnotempty(a="alpha", b="beta", g="gamma")
def foo(errs, a, b, g):
print errs
foo(3.14, "blarney", None) # prints "['g (gamma)']"
如果您没有获得所需的值,可以举例说明异常:
@argsnotempty(a="alpha", b="beta", g="gamma")
def bar(errs, a, b, g):
if errs:
raise ValueError("arguments " + ", ".join(errs) + " cannot be empty")
bar(0, None, "")
当然,您可以调整装饰器为您执行此操作,而不是在每个函数中包含样板代码。
编辑:修正了一些buggage
答案 2 :(得分:0)
要检查是否所有必需参数都传递到您的函数中,您可以创建一个将所有必需参数映射到None的字典,然后在每个方法的开头复制和更新该字典。
needed_params = {'one': None, 'two': None, 'three': None}
def my_func(**kwargs):
params = needed_params.copy()
params.update(kwargs)
for key, value in params.iteritems():
if not value:
raise TypeError("You need to provide the argument %s" % key)
result = do_stuff_here
return result
正如评论中所指出的那样,返回一个用户友好的"可能不是一个好主意。描述。相反,如果缺少参数,您可能希望引发错误。然后,您就可以在UI的其他位置处理此错误。
Kindall建议装饰者。根据您希望检查的复杂程度,我认为您可以使用比他的建议更简单的东西:
def check_needed_params(target):
needed_params = {'one': None, 'two': None, 'three': ''}
def wrapper(*args, **kwargs):
params = needed_params.copy()
params.update(kwargs)
for key, value in params.iteritems():
if not value:
raise TypeError("You need to provide the argument '%s'" % key)
return target(**params)
return wrapper
您可以使用它来识别需要检查其参数的函数,如下所示:
@check_needed_params
def adder(**kwargs):
return kwargs["one"] + kwargs["two"] + kwargs["three"]
然后,当调用此函数时,如果您提供所有结果,它将无缝地工作,但如果您不这样做,则会引发错误。
>>> adder(one=1, two=2, three=3)
6
>>> adder(one=1, two=2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "c:/Users/.../python-6940fCr.py", line 8, in wrapper
TypeError: You need to provide the argument three
答案 3 :(得分:0)
这是一个常见的&#34;很多变量&#34;图案。
def function( variable1, variable2, variable3, ..., variablen ):
"""user-friendly description of the function.
:param variable1: meaning, units, range, whatever.
:param variable2: meaning, units, range, whatever.
...
:param variablen: meaning, units, range, whatever.
:returns: range, type, whatever.
"""
# do the processing
请勿检查参数是否缺失或无效。 Python已经完成了所有需要的类型检查。只需编写代码即可。做什么特别的或额外的&#34;验证&#34;输入。 当出现异常时,这意味着输入很糟糕。
就这么简单。
通过在无关的if语句中重写所有Python类型检查,不要让它变得更复杂。
另外。
永远不要混合&#34;错误返回&#34;有效的回报。任何类型的错误输入都必须导致异常。好的投入会带来良好的价值糟糕的输入会引发异常。
就是这么简单。不要让它变得更复杂。
调用此功能时,您可以执行以下操作:
the_variables = {
'variable1': some value,
'variable2': some value,
...
'variablen': some value,
}
try:
function( **the_variables )
except Exception:
print( function.__doc__ )
有什么遗漏?你得到一个TypeError
。有什么不正确的None
或空的?你得到一个ValueError(或者它取决于TypeError)。
出现问题时,您可以打印该功能的用户友好描述。
这非常有效,并且根本不需要编程。
答案 4 :(得分:0)
你的功能听起来很大。您是否考虑过将其分解或将其变为单独的课程是否合适?
答案 5 :(得分:0)
这是我能想到的最佳答案。它需要在调用函数之前做很多准备工作,所以我不喜欢它。但是,它符合所有要求。
感谢所有参与的人,我很抱歉这个问题需要这么多修改!
def validate_parameters(params_map):
"""
map is like {foo: "this is foo"}
"""
missing_params_info = []
for k,v in params_map.items():
if not v:
missing_params_info.append(k)
return missing_params_info
# or do this if you want to use exceptions:
# if missing_params_info:
# raise TypeError('These parameters were unset: %s' % missing_params_info)
params = {}
params['foo'] = '1'
params['bar'] = '2'
params['empty'] = ''
params['empty2'] = ''
params['None'] = None
reverse_params_map = {
'this is foo' : params['foo'],
'this is bar' : params['bar'],
'this is empty' : params['empty'],
'this is empty2' : params['empty2'],
'this is None' : params['None'],
}
print validate_parameters(reverse_params_map)
bash-3.00# python /var/tmp/ck.py
['this is empty2', 'this is empty', 'this is None']
答案 6 :(得分:0)
这个问题仍然令人困惑。非常。
可能是你要求对函数的代码对象进行内省:
def noisy_typerror( func ):
def fix_exception( **kw ):
try:
# This is generally needless; mostly a waste of CPU cycles.
if not all(kw[arg] for arg in kw ):
raise TypeError
# Simply apply the function and see if a TypeError occurs
return func( **kw )
except TypeError:
required= ", ".join( func.func_code.co_varnames[:func.func_code.co_argcount] )
provided= ", ".join( "{0}={1!r}".format(k,v) for k,v in kw.items() )
raise TypeError( "{2}( {0} ) got {1}".format(required, provided,func.func_name) )
return fix_exception
@noisy_typerror
def some_func( this, that, the_other ):
a= this
b= that
print( this, that, the_other )
在旧版本的Python中应用装饰器
def the_real_func( this, that, the_other ):
etc.
some_func= noisy_typerror( the_real_func )
以下是此装饰器的一些用例
try:
some_func( this=2, that=3 )
except TypeError, e:
print e
try:
some_func( this=4 )
except TypeError, e:
print e
try:
some_func( this=2, that=3, the_other='' )
except TypeError, e:
print e
我通过打印TypeError字符串得到了这些结果。
some_func( this, that, the_other ) got this=2, that=3
some_func( this, that, the_other ) got this=4
some_func( this, that, the_other ) got this=2, the_other='', that=3