我希望有一个方便的装饰器来检查传递给方法的属性值是否不是None。然后我想在类方法中将它用作通用装饰器。为此,我写道:
def check_empty(name):
def wrap_outer(function):
def wrapped(*args, **kwargs):
if kwargs.get(name, None) is None:
raise Exception('{item} cannot be empty'.format(item=name))
return function(args, kwargs)
return wrapped
return wrap_outer
并且,该类定义为:
class Player(object):
@check_empty('name')
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
然而,这不起作用。构造函数和装饰器的模板不匹配。我们如何为构造函数创建函数装饰器?或者基于类的装饰器是更好的选择?
感谢@ ajax1234,我发现了问题。这就是我传递args
和kwargs
的方式。应该是:
def check_empty(attr):
def wrap_outer(function):
def wrapped(*args, **kwargs):
if (len(args) > 1 and args[1] is None) or (len(args)==1 and len(kwargs)==0):
raise Exception('{item} cannot be empty'.format(item=attr))
elif attr in kwargs and kwargs.get(attr, None) is None:
raise Exception('{item} cannot be empty'.format(item=attr))
return function(*args, **kwargs)
return wrapped
return wrap_outer
如果参数作为关键字参数传递或仅作为位置参数传递,则负责检查参数。
注意:它确实有一个限制,即位置参数逻辑在保持通用性质的同时不能很好地扩展。 (我们需要使用inspect.getargspec
查看位置参数的位置,然后从那里进行构建。)
答案 0 :(得分:1)
我能看到你能够做你想做的事情的唯一方法,包括位置和关键字参数,是提供位置到名称的映射,如下所示:
class NoneException(Exception):
pass
def check_none(**check):
def wrapper(fn):
def wrapped(*args, **kwargs):
for key, pos in check.items():
try:
if kwargs[key] == None:
raise NoneException(f'{key} cannot be empty')
except KeyError:
pass
try:
if args[pos] == None:
raise NoneException(f'{key} cannot be empty')
except IndexError:
pass
return fn(*args, **kwargs)
return wrapped
return wrapper
class A:
@check_none(name=1)
def __init__(self, name):
self.name = name
@check_none(phrase=1)
def test(self, phrase):
print(f'My name is {self.name}. {phrase}!')
a = A('A')
a.test('Hello world!')
try:
a.test(None)
except NoneException:
print('successfully failed')
else:
print('something went wrong')
这应该涵盖你在位置上明确命名的参数的情况,然而请注意,考虑到必须保持位置参数索引的映射,这是一个脆弱的解决方案。
如果有某种方法可以反映出来自Python内部的映射self=0, name=1, et cetera
,我建议改用它。
或者,更简单的解决方案是在您要检查的每个功能的顶部进行函数调用。
class NoneException(Exception):
pass
def check_none(*args, **kwargs):
for key, value in (*enumerate(args), *kwargs.items()):
if value == None:
raise NoneException(f'key {key} == None')
class A:
def __init__(self, name):
check_none(name)
self.name = name
答案 1 :(得分:0)
你可以试试这个:
def check_empty(attr):
def check_method(function):
def wrapped(cls, **kwargs):
if kwargs.get(attr) is None:
raise Exception('{item} cannot be empty'.format(item=attr))
return function(cls, **kwargs)
return wrapped
return check_method
class Player(object):
@check_empty('name')
def __init__(self, **kwargs):
self.__dict__ = kwargs
def __str__(self):
return self.name
p = Player(name=None)
输出:
Exception: Name cannot be empty
但是,None
以外的任何参数都可以:
p = Player(name = 'Foo')
print(p.name)
输出:
'Foo'