переопределить метод класса в Python - PullRequest
2 голосов
/ 19 ноября 2010

Я бы хотел переопределить метод класса, а не создавать подкласс / расширение из класса.

Пример:

from django.contrib import admin

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

Теперь я не хочу менять все классы (или Модели), которые расширяются от admin.ModelAdmin до NewModelAdmin. Но я не хочу изменять исходный код django.

Есть ли способ сделать это?

Ответы [ 7 ]

4 голосов
/ 19 ноября 2010

Мне не до конца ясно, что вы хотите сделать и почему вы не хотите создавать новый подкласс или иметь метод с другим именем.

Но в целом в 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"
3 голосов
/ 19 ноября 2010

Для того чтобы ваш код можно было обслуживать, лучше пойти дальше, и ваши отдельные классы ModelAdmin будут наследоваться от NewModelAdmin. Таким образом, другие разработчики, которые смотрят на ваш код (и вы, возможно, год или два спустя), могут четко видеть, откуда происходит пользовательское поведение formfield_for_dbfield, чтобы его можно было обновить при необходимости. Если вы сделаете мартовский патч admin.ModelAdmin, вам будет намного сложнее отследить проблемы или изменить поведение при необходимости позже.

3 голосов
/ 19 ноября 2010

Вы пытаетесь сделать 'исправление обезьян'?

http://mail.python.org/pipermail/python-dev/2008-January/076194.html

2 голосов
/ 19 ноября 2010

Скорее всего, ваша проблема разрешима без исправлений обезьян, что часто может иметь непредвиденные последствия.

Как вы регистрируете модели у администратора 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)
1 голос
/ 19 ноября 2010

Вы можете изменить метод класса, используя setattr() для класса - он же monkey patching.

0 голосов
/ 19 ноября 2010

Я не уверен на 100%, чего вы пытаетесь достичь, но я полагаю, что вы хотите, чтобы все администраторы, которые наследуют от models.ModelAdmin, вели себя без изменения их декларации.Единственным решением для достижения этой цели будет исправление обезьян оригинальным классом ModelAdmin, например.что-то вроде:

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

Это, безусловно, не самый рекомендуемый способ, потому что код будет трудно поддерживать и другие вещи.

0 голосов
/ 19 ноября 2010

Если вы модифицируете метод в классе, вы изменяете поведение для:

  • все экземпляры, которые разрешают свой метод для этого класса
  • все производные классы, которые разрешают свой метод для этого класса

Ваши требования являются взаимоисключающими. Вы не можете изменять поведение класса, не влияя на те объекты, которые разрешают его методы в классе.

Чтобы не изменить поведение этих других объектов, вам нужно создать метод в вашем экземпляре , чтобы он не разрешал метод в классе.

Еще одна альтернатива - полагаться на типизацию Python. Вам не нужно, чтобы объект был непосредственно связан с тем, который используется в данный момент. Вы можете переопределить интерфейс и в коде поменять вызовы старого класса на новый.

У этих методов есть компромиссы в ремонтопригодности и дизайне. Другими словами, не используйте их, если у вас нет других вариантов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...