2010-11-19 62 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)