问题描述
而不是写code每次都是这样的,我定义一个类:
类Foo(对象):
高清__init __(自我,A,B,C,D,E,F,G):
self.a =一
self.b = B
self.c = C
self.d = D
self.e = E
self.f = F
self.g = G
我可以使用。
类Foo(对象):
@autoassign
高清__init __(自我,A,B,C,D,E,F,G):
通过
两个问题
- 是否有与此相关的快捷方式或缺点陷阱?
- 有没有更好的方式来实现类似的方便?
有关于autoassign code这个bug我一些东西(主要是风格,而是一个更严重的问题):
-
autoassign
不分配
ARGS属性:类Foo(对象):
@autoassign
高清__init __(自我,A,B,C =假,*参数):
通过
A =美孚('IBM','/ tmp目录,诚然,100,101)
打印(a.args)
#AttributeError的:'富'对象有没有属性'ARGS -
autoassign
就像一个装饰。
但autoassign(* argnames)
调用
函数返回一个装饰。
为了实现这一法宝,autoassign
需要测试它的第一类型
论据。如果给我选择,我
preFER功能不考
类型它的参数。 -
似乎有相当
code量致力于建立筛
,lambda表达式中lambda表达式,
的IFilter和条件很多。如果kwargs:
排除,F =集(kwargs ['排除']),无
筛=拉姆达L:itertools.ifilter(拉姆达NV:NV [0]不排除升)
ELIF LEN(地名)== 1和inspect.isfunction(名称[0]):
F =名称[0]
筛的λ= 1:1
其他:
名称,F =设置(名称),无
筛=拉姆达L:itertools.ifilter(拉姆达NV:NV [0]名,升)我觉得可能是一个更简单的方法。 (看到
如下图)。 -
_为中
。我不认为
itertools.starmap(assigned.setdefault,
默认值):通过地图
或星图
,是为了呼吁
功能,其唯一目的是自己
副作用。它可能已被
与世俗写更清楚:重点,在defaults.iteritems)值(:
assigned.setdefault(键,值)
下面是具有相同的功能autoassign替代简单的实现(例如,可以执行包括和排除),并且解决了上述各点:
进口检查
进口functools
高清autoargs(*包括,** kwargs):
高清_autoargs(FUNC):
ATTRS,可变参数,varkw,默认= inspect.getargspec(FUNC)
高清筛(attr)使用:
如果kwargs和ATTR在kwargs ['排除']:返回False
如果不包括或ATTR中包括:返回True
其他:返回False
@ functools.wraps(FUNC)
高清封装(个体经营,* ARGS,** kwargs):
#手柄默认值
为ATTR,VAL拉链(逆转(ATTRS),反转(默认)):
如果筛(attr)使用:SETATTR(自我,ATTR,VAL)
#拉手位置参数
positional_attrs = ATTRS [1:]
为ATTR,VAL拉链(positional_attrs,参数):
如果筛(attr)使用:SETATTR(自我,ATTR,VAL)
#拉手可变参数
如果可变参数:
remaining_args = ARGS [LEN(positional_attrs):]
如果筛(可变参数):SETATTR(自我,可变参数,remaining_args)
#拉手varkw
如果kwargs:
对ATTR,VAL在kwargs.iteritems():
如果筛(attr)使用:SETATTR(自我,ATTR,VAL)
返回FUNC(个体经营,* ARGS,** kwargs)
包装回报
返回_autoargs
这里是我用来检查其行为的单元测试:
导入单元测试
进口utils_method为UM类测试(unittest.TestCase的):
高清test_autoargs(个体经营):
A类(对象):
@ um.autoargs()
高清__init __(自我,富,路径,调试= FALSE):
通过
A = A('大黄','馅饼',调试=真)
self.assertTrue(a.foo =='大黄')
self.assertTrue(a.path =='馅饼')
self.assertTrue(a.debug ==真) B类(对象):
@ um.autoargs()
高清__init __(自我,富,路径,调试=假,*参数):
通过
A = B('大黄','馅饼',真的,100,101)
self.assertTrue(a.foo =='大黄')
self.assertTrue(a.path =='馅饼')
self.assertTrue(a.debug ==真)
self.assertTrue(a.args ==(100,101)) C类(对象):
@ um.autoargs()
高清__init __(自我,富,路径,调试=假,* ARGS,** KW):
通过
A = C('大黄','馅饼',真的,100,101,详细= TRUE)
self.assertTrue(a.foo =='大黄')
self.assertTrue(a.path =='馅饼')
self.assertTrue(a.debug ==真)
self.assertTrue(a.verbose ==真)
self.assertTrue(a.args ==(100,101)) 高清test_autoargs_names(个体经营):
C类(对象):
@ um.autoargs('巴','巴兹','详细')
高清__init __(自我,富,酒吧,巴兹,详细= FALSE):
通过
一个C = C('大黄','馅饼',1)
self.assertTrue(a.bar =='馅饼')
self.assertTrue(a.baz == 1)
self.assertTrue(a.verbose ==假)
self.assertRaises(AttributeError的,GETATTR,一,'富') 高清test_autoargs_exclude(个体经营):
C类(对象):
@ um.autoargs(不含=('巴','巴兹','详细'))
高清__init __(自我,富,酒吧,巴兹,详细= FALSE):
通过
一个C = C('大黄','馅饼',1)
self.assertTrue(a.foo =='大黄')
self.assertRaises(AttributeError的,GETATTR,一个酒吧)
如果__name__ =='__main__':
unittest.main(ARGV = unittest.sys.argv + ['--verbose'])
PS。使用 autoassign
或 autoargs
是IPython的code完成兼容。
Instead of writing code like this every time I define a class:
class Foo(object):
def __init__(self, a, b, c, d, e, f, g):
self.a = a
self.b = b
self.c = c
self.d = d
self.e = e
self.f = f
self.g = g
I could use this recipe for automatic attribute assignment.
class Foo(object):
@autoassign
def __init__(self, a, b, c, d, e, f, g):
pass
Two questions:
- Are there drawbacks or pitfalls associated with this shortcut?
- Is there a better way to achieve similar convenience?
There are some things about the autoassign code that bug me (mostly stylistic, but one more serious problem):
autoassign
does not assign an'args' attribute:class Foo(object): @autoassign def __init__(self,a,b,c=False,*args): pass a=Foo('IBM','/tmp',True, 100, 101) print(a.args) # AttributeError: 'Foo' object has no attribute 'args'
autoassign
acts like a decorator.Butautoassign(*argnames)
calls afunction which returns a decorator.To achieve this magic,autoassign
needs to test the type of its firstargument. If given a choice, Iprefer functions not testthe type of its arguments.There seems to be a considerableamount of code devoted to setting up
sieve
, lambdas within lambdas,ifilters, and lots of conditions.if kwargs: exclude, f = set(kwargs['exclude']), None sieve = lambda l:itertools.ifilter(lambda nv: nv[0] not in exclude, l) elif len(names) == 1 and inspect.isfunction(names[0]): f = names[0] sieve = lambda l:l else: names, f = set(names), None sieve = lambda l: itertools.ifilter(lambda nv: nv[0] in names, l)
I think there might be a simpler way. (Seebelow).
for _ initertools.starmap(assigned.setdefault,defaults): pass
. I don't thinkmap
orstarmap
was meant to callfunctions, whose only purpose is theirside effects. It could have beenwritten more clearly with the mundane:for key,value in defaults.iteritems(): assigned.setdefault(key,value)
Here is an alternative simpler implementation which has the same functionality as autoassign (e.g. can do includes and excludes), and which addresses the above points:
import inspect
import functools
def autoargs(*include,**kwargs):
def _autoargs(func):
attrs,varargs,varkw,defaults=inspect.getargspec(func)
def sieve(attr):
if kwargs and attr in kwargs['exclude']: return False
if not include or attr in include: return True
else: return False
@functools.wraps(func)
def wrapper(self,*args,**kwargs):
# handle default values
for attr,val in zip(reversed(attrs),reversed(defaults)):
if sieve(attr): setattr(self, attr, val)
# handle positional arguments
positional_attrs=attrs[1:]
for attr,val in zip(positional_attrs,args):
if sieve(attr): setattr(self, attr, val)
# handle varargs
if varargs:
remaining_args=args[len(positional_attrs):]
if sieve(varargs): setattr(self, varargs, remaining_args)
# handle varkw
if kwargs:
for attr,val in kwargs.iteritems():
if sieve(attr): setattr(self,attr,val)
return func(self,*args,**kwargs)
return wrapper
return _autoargs
And here is the unit test I used to check its behavior:
import unittest
import utils_method as um
class Test(unittest.TestCase):
def test_autoargs(self):
class A(object):
@um.autoargs()
def __init__(self,foo,path,debug=False):
pass
a=A('rhubarb','pie',debug=True)
self.assertTrue(a.foo=='rhubarb')
self.assertTrue(a.path=='pie')
self.assertTrue(a.debug==True)
class B(object):
@um.autoargs()
def __init__(self,foo,path,debug=False,*args):
pass
a=B('rhubarb','pie',True, 100, 101)
self.assertTrue(a.foo=='rhubarb')
self.assertTrue(a.path=='pie')
self.assertTrue(a.debug==True)
self.assertTrue(a.args==(100,101))
class C(object):
@um.autoargs()
def __init__(self,foo,path,debug=False,*args,**kw):
pass
a=C('rhubarb','pie',True, 100, 101,verbose=True)
self.assertTrue(a.foo=='rhubarb')
self.assertTrue(a.path=='pie')
self.assertTrue(a.debug==True)
self.assertTrue(a.verbose==True)
self.assertTrue(a.args==(100,101))
def test_autoargs_names(self):
class C(object):
@um.autoargs('bar','baz','verbose')
def __init__(self,foo,bar,baz,verbose=False):
pass
a=C('rhubarb','pie',1)
self.assertTrue(a.bar=='pie')
self.assertTrue(a.baz==1)
self.assertTrue(a.verbose==False)
self.assertRaises(AttributeError,getattr,a,'foo')
def test_autoargs_exclude(self):
class C(object):
@um.autoargs(exclude=('bar','baz','verbose'))
def __init__(self,foo,bar,baz,verbose=False):
pass
a=C('rhubarb','pie',1)
self.assertTrue(a.foo=='rhubarb')
self.assertRaises(AttributeError,getattr,a,'bar')
if __name__ == '__main__':
unittest.main(argv = unittest.sys.argv + ['--verbose'])
PS. Using autoassign
or autoargs
is compatible with IPython code completion.
这篇关于什么是做在Python自动属性分配的最佳方式,是不是一个好主意?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!