Обезьяна-патч класс Python - PullRequest
       14

Обезьяна-патч класс Python

44 голосов
/ 22 сентября 2010

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

from module import MyClass

class ReplaceClass(object)
  ...

MyClass = ReplaceClass

Это не изменит MyClass нигде, кроме этого файла.Однако, если я добавлю такой метод

def bar():
   print 123

MyClass.foo = bar

, это сработает, и метод foo будет доступен везде.

Как полностью заменить класс?

Ответы [ 4 ]

56 голосов
/ 22 сентября 2010
import module
class ReplaceClass(object):
    ....
module.MyClass = ReplaceClass
28 голосов
/ 22 сентября 2010

Избегайте from ... import (ужасного ;-) способа получения пустых имен, когда вам чаще всего нужны квалифицированные имена.Как только вы сделаете все правильно Pythonic:

import module

class ReplaceClass(object): ...

module.MyClass = ReplaceClass

Таким образом, вы обезьяны поймаете объект module , который вам нужен и будет работать, когда этот модуль используется для других,С формой from ... вы просто не имеете объект модуля (один из способов взглянуть на явный недостаток использования from ... большинством людей), и, таким образом, вам явно хуже; -);

Единственный способ, которым я рекомендую использовать оператор from, - импортировать модуль из пакета:

from some.package.here import amodule

, так что вы все еще получаете объект модуля ибудет использовать квалифицированные имена для всех имен в этом модуле.

12 голосов
/ 20 октября 2011

Я всего лишь яйцо. , , , Возможно, это очевидно для новичков, но мне нужна была идиома from some.package.module import module.

Мне пришлось изменить один метод GenerallyHelpfulClass. Это не удалось:

import some.package.module

class SpeciallyHelpfulClass(some.package.module.GenerallyHelpfulClass): 
    def general_method(self):...

some.package.module.GenerallyHelpfulClass = SpeciallyHelpfulClass

Код выполнялся, но не использовал поведения, перегруженные на SpecialHelpfulClass.

Это сработало:

from some.package import module

class SpeciallyHelpfulClass(module.GenerallyHelpfulClass): 
    def general_method(self):...

module.GenerallyHelpfulClass = SpeciallyHelpfulClass

Я предполагаю, что идиома from ... import «получает модуль», как писал Алекс, так как он будет подхвачен другими модулями в пакете. Далее, более длинная пунктирная ссылка, кажется, переносит модуль в пространство имен с импортом по длинной пунктирной ссылке, но не меняет модуль, используемый другими пространствами имен. Таким образом, изменения в модуле импорта будут появляться только в том пространстве имен, где они были сделаны. Это как если бы было две копии одного и того же модуля, каждый из которых доступен по несколько разным ссылкам.

0 голосов
/ 22 сентября 2010
import some_module_name

class MyClass(object): 
     ... #copy/paste source class and update/add your logic

some_module_name.MyClass = MyClass

Желательно не менять имя класса при замене, потому что кто-то мог ссылаться на них, используя getattr - что приведет к сбою, как показано ниже

getattr(some_module_name, 'MyClass') ->, что приведет к сбоюесли вы заменили MyClass на ReplaceClass!

...