3 回答

TA貢獻1866條經驗 獲得超5個贊
讓我們對其進行基準測試并找出答案。為了測試這樣的事情,我喜歡使用我編寫的模塊:timerit。
import timerit
class Animal():
def add(self):
self.weight = 10
self.color = 'Black'
class Bird(Animal):
def add(self):
self.feather_type = 'Long'
super().add()
b = Bird()
b.add()
ti = timerit.Timerit(1000000, bestof=100, verbose=2)
for timer in ti.reset('Access weight'):
with timer:
b.weight
for timer in ti.reset('Access color'):
with timer:
b.color
for timer in ti.reset('Access feather_type'):
with timer:
b.feather_type
這導致
Timed Access weight for: 1000000 loops, best of 100
time per loop: best=347.005 ns, mean=370.222 ± 17.2 ns
Timed Access color for: 1000000 loops, best of 100
time per loop: best=350.992 ns, mean=367.194 ± 9.5 ns
Timed Access feather_type for: 1000000 loops, best of 100
time per loop: best=348.984 ns, mean=367.680 ± 11.9 ns
因此,不,它們之間似乎沒有任何顯著差異。

TA貢獻1811條經驗 獲得超6個贊
實例屬性存儲在實例中,因此繼承在這里完全無關緊要。請記住,當在子實例上調用父類方法時,該方法作為第一個參數 ( self) 得到的是子實例:
>>> class Foo:
... def __init__(self):
... print("In Foo.__init__, self is {}".format(self))
...
>>> class Bar(Foo): pass
...
>>> b = Bar()
In Foo.__init__, self is <__main__.Bar object at 0x7fd230244f60>
>>>
將它們作為局部變量存儲在子類函數中,然后訪問它們會更好嗎?(如果多次使用)
僅適用于緊密循環中使用的屬性(屬性解析比局部變量解析慢一點)并且分析顯示此時存在瓶頸。但也不要指望大幅加速......
實際上,如果您不得不擔心這種微優化,那么真正的解決方案是重新考慮您的設計和實現,或者用 C 重新實現代碼的關鍵部分。
與代碼中一樣,變量未在init方法中初始化。這會使程序變慢嗎
不是真的,除了調用的開銷obj.add()
。但是:
這樣做是因為,并非所有操作都需要類的所有屬性。因此,何時并根據需要對它們進行初始化和使用。
錯誤的設計。如果您想對某些屬性進行延遲初始化,請使用一個property
或一些自定義描述符。這將確保您的對象無論發生什么都將始終具有預期的屬性。
如果父類中有很多變量 10+(包括數組和數據模型對象)
一個類中的“很多”屬性通常是一種設計氣味。這里沒有硬性規定——某些情況確實需要相當多的屬性——但是你的類可能有太多的責任,最好將其重構為一組最小的類,每個類都有一個單一的、明確定義的責任。
不,將父類屬性初始化復制粘貼到子類無論如何都不會加速您的代碼 - 它只會使維護變得更加困難,并增加在更改父類或子類時引入錯誤的風險。我個人認為這是一個完整的 WTF,但我并不以我與生俱來的外交意識而聞名;-)
編輯:
實際上我在這里沒有提到的一件事,我在 init 之外創建變量的另一個主要原因是因為我在我的代碼中使用了工廠設計模式。我正在使用動態創建類
def _create(pkg): exec('import api.' + pkg + 'Helper as Creator'); return eval('Creator' + '.' + pkg + 'Helper()' )
呃……你可能有興趣了解 Python 的一些特性,比如importlib.import_module
和getattr
。作為一般規則,每當您考慮使用eval
or時exec
,請確保有更好(=> 更安全、更明確且更易于維護)的解決方案。我已經使用 Python 20 多年了(用于個人和專業項目),我仍然需要找到一個我有正當理由使用eval
或exec
.
此外,您沒有發布實際上“動態創建類”但動態創建類不會施加任何限制或解決方法(與“靜態”定義相比)的代碼部分 - 您仍然可以為您的類提供適當的初始化程序,屬性或任何其他自定義描述符等。如果您還使用exec??
/eval
來構建您的類,那么這里還有更好的方法。
我的2美分...

TA貢獻1155條經驗 獲得超0個贊
實例屬性都將在實例對象本身上創建。父/子關系在那里無關緊要。
b.add()
這調用:
def add(self): ...
self
這里將b
?,F在調用super.add()
,這又是:
def add(self): ...
self
這里仍然會b
。所有屬性都直接添加到同一個對象。
可以說解決super().add()
呼叫將是一個輕微的開銷,但它絕對可以忽略不計。如果存在的話,訪問屬性的任何區別也會如此。
添加回答
舉報