簡體   English   中英

將參數分配到屬性的Pythonic方法?

[英]Pythonic way to assign the parameter into attribute?

示例代碼如下:

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個參數,則會受到影響。 有沒有人對這個更方便的方法有想法?

你可以這樣做:

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集。

顯式優於隱式

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

有很多優點

def assign(self, **kwargs)
  • 它是自我記錄的
  • 如果將無效參數傳遞給assign則會引發有用的TypeError
  • 可以使用位置和關鍵字參數調用assign

值得贊揚的是,OP發布的代碼完全是明確的,盡管if statement是單調的。 要減少單調,你可以使用這樣的東西:

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')

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

使用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,) ???
說真的嗎?
哦,哎呀!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM