2010-11-19 207 views
2

我想重寫一個類方法,而不是創建子類/從類擴展。python中覆蓋類的方法

一個例子:

from django.contrib import admin 

class NewModelAdmin(admin.ModelAdmin): 
    def formfield_for_dbfield(self, db_field, **kwargs): 
     # some custom stuff 

現在我不想改變所有這些擴展從admin.ModelAdminNewModelAdmin類(又名型號)。但我不想修改原始的django代碼。

有沒有辦法做到這一點?

+0

一旦你定義在'NewModelAdmin'的方法,你有什麼打算用它做什麼? – 2010-11-19 16:18:43

回答

1

您可以更改的類使用setattr()類方法 - 又名monkey patching

3

爲了保持代碼的可維護性,最好繼續並讓您的個人ModelAdmin類從NewModelAdmin繼承。這樣,其他開發人員可以清楚地看到自定義formfield_for_dbfield行爲源自的位置,以便在需要時可以更新它(可能會在一兩年後)。如果你使用monkey-patch admin.ModelAdmin,它會使追蹤問題或稍後需要時改變行爲變得更加困難。

3

我不完全清楚你想做什麼,爲什麼你不想創建一個新的子類或者有一個不同名字的方法。

但一般在Python中,你可以這樣做:如果你修改的類的方法你修改行爲

class MyClass(object): 
    def print_hello(self): 
     print "not hello" 

def real_print_hello(): 
    print "hello" 

x = MyClass() 
x.print_hello() # "not hello" 
setattr(x, "print_hello", real_print_hello) 
x.print_hello() # "hello" 
0

  • 所有情況下,其解決他們的方法爲該類
  • 將其方法解析爲該類的所有派生類

您的要求是相互排斥的。您不能修改類的行爲,而不會影響將其方法解析爲類的那些對象。

爲了修改你想這些其他對象的行爲創造方法在實例,以便它不能解決它在類的方法。

另一種選擇是依靠Python的鴨子打字。您不需要該對象與當前使用的對象直接相關。您可以重新實現接口,並在代碼中將新的調用換成舊類。

這些技術在可維護性和設計方面有折衷。換句話說,除非你沒有別的選擇,否則不要使用它們。

0

我不是100%確定你想達到什麼,但我想你想表現出所有管理員從models.ModelAdmin繼承而不必更改他們的聲明。實現這一目標的唯一解決方案是猴子修補原始ModelAdmin類,例如。像這樣:

setattr(admin.ModelAdmin, 'form_field_for_dbfield', mymethod) 

這肯定不是最值得推薦的方式,因爲代碼將很難維護和其他的東西。

2

機會很好,您的問題是可以解決的,沒有猴子補丁,這往往會產生意想不到的後果。

你如何註冊與Django管理員模型?

如果您正在使用這個方法:

admin.site.register(FooModel) #uses generic ModelAdmin 

你需要來改變這NewModelAdmin的子類的許多樣板實例,這看起來像這樣的問題:

class FooModelAdmin(NewModelAdmin): 
    pass #does nothing except set up inheritance 
admin.site.register(FooModel, FooModelAdmin) 

這真的很羅嗦,如果你有很多模型可能需要很多時間來實現,所以編寫一個包裝函數來編程:

def my_admin_register(model): 
    class _newmodeladmin(ModelAdmin): 
     def your_overridden_method(*args, **kwargs): 
      #do whatever here 
    admin.site.register(model, _newmodeladmin) 

然後,你可以使用這個像這樣:

my_admin_register(FooModel)