這是問題的作者。我發現了一個非常偷偷摸摸的解決方案,但我不知道有另一種方法來做到這一點。 (我正在使用python 3.4。)
我將從遇到的問題開始。
首先,我想到了完全覆蓋該屬性,像這樣:
鑑於該類
class A(object):
def __init__(self):
self._value = 42
@property
def value(self):
return self._value
,你可以在做這樣的事情完全寫入屬性:
a = A()
A.value = 31 # This just redirects A.value from the @property to the int 31
a.value # Returns 31
問題是,這是在類級而不是在實例級完成的,所以如果我創建A的新實例,則會發生這種情況:
a2 = A()
a.value # Returns 31, because the class itself was modified in the previous code block.
我想這回a2._value
因爲a2
是A()
一個全新的實例,因此不應該由我做了什麼,以a
的影響。
解決方法是用新屬性覆蓋A.value
,而不是我想將實例_value
分配給的內容。我瞭解到,您可以使用特殊的getter
,setter
和deleter
方法(請參閱here)創建一個新屬性,該屬性使用舊屬性實例化自己。所以,我可以覆蓋A
的價值屬性,並通過這樣做二傳手吧:
def make_setter(name):
def value_setter(self, val):
setattr(self, name, val)
return value_setter
my_setter = make_setter('_value')
A.value = A.value.setter(my_setter) # This takes the property defined in the above class and overwrites the setter with my_setter
setattr(A, 'value', getattr(A, 'value').setter(my_setter)) # This does the same thing as the line above I think so you only need one of them
這是一切都一樣好,只要原班有什麼東西在原始類的屬性定義非常簡單(在這種情況只是return self._value
)。然而,一旦你變得更加複雜,像我一樣return self.data._value
,事情變得討厭 - 就像@BrenBarn在他對我的帖子的評論中說的。我使用inspect.getsourcelines(A.value.fget)
函數來獲取包含返回值並解析它的源代碼行。如果我沒有解析字符串,我提出了一個例外。結果看起來是這樣的:
def make_setter(name, attrname=None):
def setter(self, val):
try:
split_name = name.split('.')
child_attr = getattr(self, split_name[0])
for i in range(len(split_name)-2):
child_attr = getattr(child_attr, split_name[i+1])
setattr(child_attr, split_name[-1], val)
except:
raise Exception("Failed to set property attribute {0}".format(name))
它似乎工作,但也有可能錯誤。
現在的問題是,如果事情失敗了怎麼辦?這取決於你,並從這個問題中脫離軌道。就我個人而言,我做了一些討厭的東西,包括創建一個繼承自A的新類(讓我們稱之爲B類)。那麼如果setter爲A工作,它將適用於B的實例,因爲A是基類。但是,如果它不工作(因爲在規定的返回值是討厭的東西),我在類跑了settattr(B, name, val)
B.這通常發生變化的B創建的所有其他情況下(如在第2碼在這篇文章中),但我動態地使用type('B', (A,), {})
創建B,並且只用它一次,所以改變類本身對其他任何東西都沒有影響。
有很多的黑魔法類的東西會在這裏我想,但它是在當天很酷,很多才多藝左右,我用它了。這些都不是可複製代碼,但如果你理解它,那麼你可以編寫你的修改。
我真的希望/希望有更好的辦法,但我不知道其中之一。也許從類創建的元類或描述符可以爲你做出一些不錯的魔法,但我還不太瞭解它們。
評論贊賞!
如果這是它存在的唯一位置,那麼從函數內部提取'another_name'的東西沒有任何理智的方法。 – BrenBarn