5

示例代码如下:

def assign(self, input=None, output=None, param=None, p1=None, p2=None):
    if input:
        self.input = input
    if output:
        self.output = output
    if param:
        self.param = param
    if p1:
        self.p1 = p1
    if p2:
        self.p2 = p2

虽然这看起来很清楚,但如果这个函数有 10 个参数,它就会受到影响。有没有人有关于更方便的方法的想法?

4

4 回答 4

7

您可以执行以下操作:

def assign(self,**kwargs):
    for k,v in kwargs.items():
        if v:
           setattr(self,k,v)

这非常简单,适用于许多情况。如果您想维护一组关键字,您将接受并在其余部分引发 TypeError:

#python2.7 and newer
def assign(self,allowed_kwargs={'foo','bar','baz'},**kwargs):
    if kwargs.keysview() - allowed_kwargs:
        raise TypeError('useful message here...')
    for k in allowed_kwargs:
        setattr(self,k,kwargs[k])

这在某种程度上也是可检查的,因为用户将看到一组允许的 kwargs。

于 2013-03-10T02:34:23.377 回答
1

显式优于隐式

def assign(self, input=None, output=None, param=None, p1=None, p2=None):

有很多优势

def assign(self, **kwargs)
  • 它是自我记录的
  • 如果TypeError将无效参数传递给 assign.
  • assign可以使用位置参数和关键字参数调用

值得称赞的是,OP 发布的代码是完全明确的,尽管if- 语句是单调的。为了减少单调,你可以使用这样的东西:

class Foo(object):
    def assign(self, input=None, output=None, param=None, p1=None, p2=None):
        for name in 'input output param p1 p2'.split():
            val = vars()[name]
            if val is not None:
                setattr(self, name, val)

foo = Foo()
foo.assign(p1=123, p2='abc')
于 2013-03-10T02:39:12.147 回答
0

python 的一大优点是它的交互式解释器。当你写这样的代码时:

>>> def assign(self, input=None, output=None, param=None, p1=None, p2=None):
...     pass
... 

很容易弄清楚你应该如何使用这个功能:

>>> help(assign)
Python Library Documentation: function assign in module __main__

assign(self, input=None, output=None, param=None, p1=None, p2=None)

通过对比:

>>> def assign2(self, **kwargs):
...     pass
... 

给出:

>>> help(assign2)
Python Library Documentation: function assign2 in module __main__

assign2(self, **kwargs)

我希望你明白为什么第一种形式更可取。但是您仍然希望避免将所有内容写两次(在参数和正文中)。

第一个问题是你为什么要编写这种性质的代码?我发现这是一个非常常见的情况,我想要一个带有一堆属性的类,它将携带,但这些属性的集合基本上是固定的。在最常见的情况下,这些属性在对象的生命周期内永远不会改变;在这种情况下,python 有一个内置的帮助器!

>>> import collections
>>> Assignment = collections.namedtuple('Assignment', 'input output param p1 p2')
>>> assign = Assignment(None, None, None, None, None)._replace
>>> assign(p1=10)
Assignment(input=None, output=None, param=None, p1=10, p2=None)
>>> help(Assignment)
Python Library Documentation: class Assignment in module __main__

class Assignment(__builtin__.tuple)
 |  Assignment(input, output, param, p1, p2)
 |  
... SNIP

namedtuple是常规类,您可以从它们继承以赋予它们特殊的行为。不幸的是,它们是不可变的,如果您碰巧需要它,您将需要另一种技术;但是您几乎总是应该首先找到命名元组。否则,我们可以使用其他魔法;我们可以得到所有的局部变量,它们在函数开始时只包含参数:

>>> class Assignable(object):
...     def assign(self, input=None, output=None, param=None, p1=None, p2=None):
...         _kwargs = vars()
...         _kwargs.pop('self')
...         vars(self).update((attr, value) for attr, value in _kwargs.items() if value is not None)
... 
>>> a = Assignable()
>>> vars(a)
{}
>>> a.assign(p1=6)
>>> vars(a)
{'p1': 6}
>>> a.p1
6

而且help()文字还是很有帮助的!

>>> help(a.assign)
Python Library Documentation: method assign in module __main__

assign(self, input=None, output=None, param=None, p1=None, p2=None) method of __main__.Assignable instance
于 2013-03-10T13:51:51.300 回答
0

使用 mgilson 和 unutbu 的解决方案,编写所有类型的调用的可能性就消失了。

在我的以下解决方案中,保留了这种可能性:

class Buu(object):
    def assign(self,
               input=None, output=None,
               param=None,
               p1=None, p2=None,
               **kw):
        for k,v in locals().iteritems():
            if v not in (self,None,kw):
                if v == (None,):
                    setattr(self,k,None)
                else:
                    setattr(self,k,v)
        for k,v in kw.iteritems():
            setattr(self,k,v)

buu = Buu()

buu.assign(None,(None,), p1=[])
print "buu's attributes:",vars(buu)
print

buu.assign(1,p2 = 555, xx = 'extra')
print "buu's attributes:",vars(buu)

结果

buu's attributes: {'output': None, 'p1': []}

buu's attributes: {'p2': 555, 'output': None, 'xx': 'extra', 'p1': [], 'input': 1}

顺便说一句,当编码人员将None参数作为默认参数时,这是因为他预见到在任何情况下都不会有必要将其None作为在执行期间真正有影响的重要参数传递。
因此,我认为None作为真正重要的论点传递的观点是一个错误的问题。
但是,在上面的代码中,通过使用约定来避免这个问题,即如果None必须创建具有值的新属性,则参数应该是(None,)

如果有人想通过(None,)???
严重地 ?
哎呀!

于 2013-03-10T22:05:07.187 回答