3 回答

TA貢獻(xiàn)1866條經(jīng)驗(yàn) 獲得超5個(gè)贊
讓我們對(duì)其進(jìn)行基準(zhǔn)測(cè)試并找出答案。為了測(cè)試這樣的事情,我喜歡使用我編寫的模塊: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
這導(dǎo)致
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貢獻(xiàn)1811條經(jīng)驗(yàn) 獲得超6個(gè)贊
實(shí)例屬性存儲(chǔ)在實(shí)例中,因此繼承在這里完全無關(guān)緊要。請(qǐng)記住,當(dāng)在子實(shí)例上調(diào)用父類方法時(shí),該方法作為第一個(gè)參數(shù) ( self) 得到的是子實(shí)例:
>>> 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>
>>>
將它們作為局部變量存儲(chǔ)在子類函數(shù)中,然后訪問它們會(huì)更好嗎?(如果多次使用)
僅適用于緊密循環(huán)中使用的屬性(屬性解析比局部變量解析慢一點(diǎn))并且分析顯示此時(shí)存在瓶頸。但也不要指望大幅加速......
實(shí)際上,如果您不得不擔(dān)心這種微優(yōu)化,那么真正的解決方案是重新考慮您的設(shè)計(jì)和實(shí)現(xiàn),或者用 C 重新實(shí)現(xiàn)代碼的關(guān)鍵部分。
與代碼中一樣,變量未在init方法中初始化。這會(huì)使程序變慢嗎
不是真的,除了調(diào)用的開銷obj.add()
。但是:
這樣做是因?yàn)?,并非所有操作都需要類的所有屬性。因此,何時(shí)并根據(jù)需要對(duì)它們進(jìn)行初始化和使用。
錯(cuò)誤的設(shè)計(jì)。如果您想對(duì)某些屬性進(jìn)行延遲初始化,請(qǐng)使用一個(gè)property
或一些自定義描述符。這將確保您的對(duì)象無論發(fā)生什么都將始終具有預(yù)期的屬性。
如果父類中有很多變量 10+(包括數(shù)組和數(shù)據(jù)模型對(duì)象)
一個(gè)類中的“很多”屬性通常是一種設(shè)計(jì)氣味。這里沒有硬性規(guī)定——某些情況確實(shí)需要相當(dāng)多的屬性——但是你的類可能有太多的責(zé)任,最好將其重構(gòu)為一組最小的類,每個(gè)類都有一個(gè)單一的、明確定義的責(zé)任。
不,將父類屬性初始化復(fù)制粘貼到子類無論如何都不會(huì)加速您的代碼 - 它只會(huì)使維護(hù)變得更加困難,并增加在更改父類或子類時(shí)引入錯(cuò)誤的風(fēng)險(xiǎn)。我個(gè)人認(rèn)為這是一個(gè)完整的 WTF,但我并不以我與生俱來的外交意識(shí)而聞名;-)
編輯:
實(shí)際上我在這里沒有提到的一件事,我在 init 之外創(chuàng)建變量的另一個(gè)主要原因是因?yàn)槲以谖业拇a中使用了工廠設(shè)計(jì)模式。我正在使用動(dòng)態(tài)創(chuàng)建類
def _create(pkg): exec('import api.' + pkg + 'Helper as Creator'); return eval('Creator' + '.' + pkg + 'Helper()' )
呃……你可能有興趣了解 Python 的一些特性,比如importlib.import_module
和getattr
。作為一般規(guī)則,每當(dāng)您考慮使用eval
or時(shí)exec
,請(qǐng)確保有更好(=> 更安全、更明確且更易于維護(hù))的解決方案。我已經(jīng)使用 Python 20 多年了(用于個(gè)人和專業(yè)項(xiàng)目),我仍然需要找到一個(gè)我有正當(dāng)理由使用eval
或exec
.
此外,您沒有發(fā)布實(shí)際上“動(dòng)態(tài)創(chuàng)建類”但動(dòng)態(tài)創(chuàng)建類不會(huì)施加任何限制或解決方法(與“靜態(tài)”定義相比)的代碼部分 - 您仍然可以為您的類提供適當(dāng)?shù)某跏蓟绦颍瑢傩曰蛉魏纹渌远x描述符等。如果您還使用exec??
/eval
來構(gòu)建您的類,那么這里還有更好的方法。
我的2美分...

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