昨天最後的「下篇預告」,筆者突然冒出一句:Python是可以在外部修改私有屬性的。這裡的「修改」,昨天沒有交代得很清楚,其實筆者想說的是:Python是可以使用「物件.屬性」的方式,來直接修改物件的私有屬性。
class Cult(): # 邪教
def __init__(self, name: str):
self.__name = name # private attribute
def get_name(self) -> str: # public method
return self.__name
def change_name(self, name: str): # public method
self.__name = name
cult = Cult('奧修教')
print(f'\n建立物件後的教名初值:{cult.get_name()}') # 1) 注意這裡是呼叫get_name()而非以cult.__name取值。
cult.__name = '天堂之門' # 2) 直接賦值,沒有報錯耶。
print(f'\n以cult.__name表示式賦值:{cult.__name=} (看來修改成功)') # 3) 修改過後竟然就可以用cult.__name取值。
setattr(cult, '__name', '大衛教派') # 4) 改用setattr()函數測試。
print(f'利用 setattr() 函數賦值:{cult.__name=} (看來修改成功)') # 5) 看來也更改成功。
print(f' __name真正的值:{cult.get_name()} (其實沒有改到)') # 6) 其實沒用,仍然是"奧修教"。
print('\n呼叫class提供的change_name()方法修改:')
cult.change_name('太陽聖殿教')
print(f' __name真正的值:{cult.get_name()} (這次才真的更改成功)') # 7) 這次才真的更改成功。
輸出如下:__name
的初值是"奧修教"。__name
的值。迷二:明明之前說了n遍:「不能用物件.屬性」來取得私有屬性的值,何以在賦值成功之後,變成可以了?__name
值卻依然是"奧修教",並沒有更改。各位要知道:用類別提供的方法來取值,取到的才是真正的值。__name
的值呢?Cult
,有一個private屬性__name
,Python內部會將此屬性的名稱轉為_Cult__name
。cult.__name = '天堂之門'
做的事,其實不是修改當初的私有屬性__name
,而是創造了另外一個屬性。這個新屬性和原來的私有屬性__name
無關。不信可以用print(cult.__dict__)
來觀看cult的所有屬性,看過就真相大白了:class Cult(): # 邪教
def __init__(self, name: str):
self.__name = name # private attribute
def get_name(self) -> str: # public method
return self.__name
def change_name(self, name: str): # public method
self.__name = name
cult = Cult('奧修教')
print(f'\n建立物件後的教名初值:{cult.get_name()}') # 1) 注意這裡是呼叫get_name()而非以cult.__name取值。
cult._Cult__name = '天堂之門' # 2) 直接賦值,沒有報錯耶。
print(f'\n以_Cult__name表示式賦值:{cult._Cult__name=}') # 3) 修改過後竟然就可以用cult.__name取值。
print(f' __name真正的值:{cult.get_name()} (真的修改成功)') # 6) 其實沒用,仍然是"奧修教"。
setattr(cult, '_Cult__name', '大衛教派') # 4) 改用setattr()函數測試。
print(f'\n利用 setattr() 函數賦值:{cult._Cult__name=}') # 5) 看來也更改成功。
print(f' __name真正的值:{cult.get_name()} (真的修改成功)') # 6) 其實沒用,仍然是"奧修教"。
# print('\n呼叫class提供的change_name()方法修改:')
# cult.change_name('太陽聖殿教')
# print(f' __name真正的值:{cult.get_name()} (這次才真的更改成功)') # 7) 這次才真的更改成功。
輸出: