2013-10-23 48 views
3

在Python中,dict對象有一個「pop」方法,該方法返回並從字典中移除一個鍵,如果該鍵不存在則使用可選的默認值。如何在python中實現屬性彈出

對一般對象屬性做這件事的最好方法是什麼?

我在想:

my_obj.__dict__.pop('key_name', default) 

應該是一個不錯的選擇,但我擔心,直接屏蔽對象的字典可能有意想不到的副作用,我是不知道的。有更好的選擇嗎?

+2

你爲什麼要這樣做?在Python中以這種方式處理對象屬性通常不是一個好主意。 – user2357112

+0

你到底在問什麼?我的意思是,你會使用'my_obj.pop('key_name',default)',然後你會實現一些對你的對象有意義的事情,如果它代表離子風暴或冰激凌卡車... –

+1

僅僅因爲對象的屬性是用字典實現的,並不意味着對象本身支持「流行」操作是有意義的。面向對象設計的一部分是每個類的實例共享由類定義的某些屬性。從一個對象中去除這樣的屬性,而不是另一個對象打破了這種設計。 – chepner

回答

2

(對於具有__dict__的對象)「彈出」屬性與將它從__dict__中彈出相同,因此您的建議實現是正確的。

編輯:@Erik正確指出,使用__dict__.pop可以提高KeyError,其中相應的例外是AttributeError。所以更好的實現會添加try/catch/reraise-as-AttributeError。

我只想指出的是,你正在試圖做的是「啪」一個對象的屬性,不是關鍵

+0

好吧,這可能是一個愚蠢的問題,但...並不是每個新風格的對象都有''__dict__'''屬性?它內置於語言本身。 – galarant

+0

沒有。例如如果他們使用[slots](http://stackoverflow.com/questions/472000/python-slots)或者如果它們是擴展中實現的類型(例如numpy數組) – shx2

2

編輯:一個可能更快,螺紋與KeyErrorAttributeError正確映射安全的替代品:

_NO_DEFAULT = object() # so that None could be used as a default value also 

def popattr(obj, name, default=_NO_DEFAULT): 
    try: 
     return obj.__dict__.pop(name) 
    except KeyError: 
     if default is not _NO_DEFAULT: 
      return default 
     raise AttributeError("no attribute '%s'" % name) 
     # or getattr(obj, name) to generate a real AttributeError 

(前面的答案)

像這樣的東西應該工作:

def popattr(obj, name): 
    ret = getattr(obj, name) 
    delattr(obj, name) 
    return ret 

雖然obj.__dict__.pop(name)也可以,但是如果不存在屬性,你會得到KeyError而不是AttributeError,我會說後者在對象屬性訪問方面是語義上正確的; KeyError用於字典,但您不是真的訪問字典;您使用__dict__的事實僅僅是屬性彈出的實現細節,應該隱藏,這就是popattr所做的。

+0

del obj.name將不起作用... – Ben

+0

@Ben:對不起,我的不好;與OP建議的一樣,使用'obj .__ dict __。pop'固定(並簡化) –

+0

對於更快和更原子(因此線程安全)更好。你關於'KeyError'和'AttributeError'的觀點雖然不錯。 – shx2