[英]python propery: list-like object
我正在嘗試創建一個具有類似列表的屬性的對象。 這就是我的意思。
class Unit:
def __init__(self):
self.val = 0
class Bundle:
def __init__(self, N=3):
self.units = [ Unit() for i in range(N) ]
def getvals(self):
return [ unit.val for unit in self.units ]
def setvals(self, vals):
for i, val in enumerate(vals):
self.units[i].val = val
vals = property(getvals, setvals)
現在,此對象的行為不符合預期。
>>> b = Bundle()
>>> b.setvals([1,2,3])
>>> print b.vals, b.getvals()
[1, 2, 3] [1, 2, 3]
>>> b.vals = [4,5,6]
>>> print b.vals, b.getvals()
[4, 5, 6] [1, 2, 3]
所以語句“b.vals = x”和“b.setvals(x)”不等同。 你能告訴我為什么,以及如何讓它表現得正常嗎?
在Python 2中, property
僅適用於新樣式對象; 你的Bundle
類必須從object
繼承:
class Bundle(object):
...
一旦您進行了更正,該物業將按預期工作:
>>> b.vals = [4,5,6]
>>> b.vals
[4, 5, 6]
>>> b.getvals()
[4, 5, 6]
>>> [unit.val for unit in b.units]
[4, 5, 6]
只是為了完成Martijn Pieters的回答 ,這可能是你想要的答案,我不禁展示你可以用Python做的一些非常奇特的事情,當我發現它們時讓我非常驚訝。 我認為你可能會覺得它們很有用,或者給你一些未來的想法。
list
是一個對象,因此您可以從list
擴展您的類 這將使您的“Bundle”對象繼承內置list
對象中的所有方法,並允許您向其添加新方法。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class Unit(object):
def __init__(self):
self.val = 0
def __repr__(self):
return "%s %s val=%s" % (type(self), hex(id(self)), self.val)
class Bundle(list):
def __init__(self, N=3):
super(Bundle, self).__init__()
self.extend([ Unit() for i in range(N) ])
@property
def vals(self):
return [ unit.val for unit in self]
@vals.setter
def vals(self, vals):
vals = vals[0:min(len(self), len(vals))] # if len(vals) > len(self), self[i] would break
for i, val in enumerate(vals):
self[i].val = val
if __name__ == "__main__":
bundle = Bundle()
print "Bundle: %s" % bundle
newUnit = Unit()
bundle.append(newUnit)
print "Bundle: %s" % bundle
bundle.vals = [1, 2, 3, 4, 5, 6]
print "Bundle (reassigned): %s" % bundle
請注意,我更改了一些屬性定義,使它們成為裝飾器,但基本思想保持不變。
list
的對象表現為list
: 請注意,此代碼僅用於示例目的。 它有一個可怕的設計,一個可怕的OOP使用,它的行為將是非常混亂的每個人(甚至對於Guido van Rossum ......好吧,也許不適合他,但我敢肯定,如果他看到它,他會哭真正的程序)這是......糟糕的代碼...但我認為它有助於理解你可以做什么來覆蓋內置方法。 此外,它缺少很多方法可以覆蓋Bundle
類作為一個真正的list
對象,但我有點累了:-)檢查Emulating容器類型和下一點, 用於模擬 Python文檔的序列類型的其他方法一個完整的參考。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class Unit(object):
def __init__(self):
self.val = 0
def __repr__(self):
return "%s %s val=%s" % (type(self), hex(id(self)), self.val)
class OtherUnit(object):
def __init__(self):
self.whatever = "hello"
def __repr__(self):
return "%s %s whatever=%s" % (type(self), hex(id(self)), self.whatever)
class Bundle(object):
def __init__(self, N=3):
self.units = [ Unit() for i in range(N) ]
self.otherUnits = [ OtherUnit() for i in range(N) ]
def __repr__(self):
return "%s" % (self.units + self.otherUnits)
def __len__(self):
return len(self.units) + len(self.otherUnits)
def __iter__(self):
for item in (self.units + self.otherUnits):
yield item
def __contains__(self, value):
if isinstance(value, Unit):
return value in self.units
elif isinstance(value, OtherUnit):
return value in self.otherUnits
elif isinstance(value, int):
return value in [unit.val for unit in self.units]
elif isinstance(value, str):
return value in [otherUnit.whatever for otherUnit in self.otherUnits]
else:
return False
def __getitem__(self, index):
assert index >= 0, "Can't accept negative indexes (%s)" % indexes
if index < len(self.units):
return self.units[index]
else:
return self.otherUnits[index - len(self.units)] #Will raise index error if too big
def append(self, thing):
if isinstance(thing, Unit):
self.units.append(thing)
elif isinstance(thing, OtherUnit):
self.otherUnits.append(thing)
else:
raise TypeError("Can't accept %s" % type(thing))
@property
def vals(self):
return [ unit.val for unit in self.units] + [ otherUnit.whatever for otherUnit in self.otherUnits ]
@vals.setter
def vals(self, vals):
insertionPointUnits = 0
insertionPointOtherUnits = 0
for i, val in enumerate(vals):
if isinstance(val, int):
self.units[insertionPointUnits].val = val
insertionPointUnits += 1
elif isinstance(val, str):
self.otherUnits[insertionPointOtherUnits].whatever = val
insertionPointOtherUnits += 1
if __name__ == "__main__":
bundle = Bundle()
print "Bundle: %s" % bundle
newUnit = Unit()
bundle.append(newUnit)
print "Bundle: %s" % bundle
bundle.vals = [1, 2, "bye", 3, "how are you", 4, "doing ok"]
print "Bundle (reassigned): %s" % bundle
print "Bundle has %s items" % len(bundle) #Thanks to overwritting __len__
for i, item in enumerate(bundle):
print "bundle[%s]: %s" % (i, item) #Thanks to overwritting __iter__
print "Does 'bundle' contain 'bye'?: %s" % ('bye'in bundle) #Thanks to overwritting __contains__
print "Does 'bundle' contain 5?: %s" % (5 in bundle) #Thanks to overwritting __contains__
print "Item 1 (should be Unit with val '2': %s" % bundle[1] #Thanks to overwritting __getitem__
print "Item 5 (should be OtherUnit with val 'how are you' (4 Units + 1 OtherUnit... then ours!): %s" % bundle[5] #Thanks to overwritting __getitem__
try:
print "Item 9 (should raise IndexError): %s" % bundle[9]
except IndexError, ie:
print "Wooops: %s" % ie
希望這有點幫助。 享受Python的樂趣!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.