2016-06-06 3 views
1

Я хотел бы сделать копию класса, в то время как обновление всех своих методов для обозначения нового набора __globals__Как сделать глубокую копию класса Python?

я что-то вроде ниже думать, однако в отличие от types.FunctionType, конструктор types.UnboundMethodType не принимает __globals__, любые предложения, как обойти это?

def copy_class(old_class, new_module): 
    """Copies a class, updating __globals__ of all methods to point to new_module""" 

    new_dict = {} 
    for name, entry in old_class.__dict__.items(): 
    if isinstance(entry, types.UnboundMethodType): 
     entry = types.UnboundMethodType(name, None, old_class.__class__, globals=new_module.__dict__) 
    new_dict[name] = entry 
    return type(old_class.name, old_class.__bases__, new_dict) 

ответ

1

Значения __dict__ являются функциями, а не несвязанными методами. Объекты unbound метода получаются только при доступе к атрибуту. Если вы :, видя объекты unbound метода в __dict__, что-то странное произошло с вашим объектом класса до того, как эта функция дошла до него.

+0

Я не вижу несвязанных методов в своем dict .... Должен ли я просто копировать элементы FunctionType «dict», как обычные функции? –

+0

@ Ярослав Булатов: Да, поскольку они являются регулярными функциями. – user2357112

1

Я не знаю о вас, но я вообще не люблю использовать types для чего-либо иного, кроме проверки типа (что я не делаю очень часто ;-). Я бы предпочел inspect ...

Я должен предисловие к этому коде, сказав, что я надеюсь, что у вас есть действительно веская причина для этого ;-) - мне кажется, что это просто подклассы и переопределение свойства класса должны сделать работу намного элегантнее ... Однако, если вы действительно хотите скопировать класс - Почему бы просто не запустить его снова в новом пространстве имен?

Я соединил следующие простые модули:

# test.py 
# Just some test data 
FOO = 1 

class Bar(object): 
    def subclass_method(self): 
    print('Hello World!') 

class Foo(Bar): 
    def method(self): 
    return FOO 

А потом что-то делать тяжелую работу:

import sys 
import inspect 

def copy_class(cls, new_globals): 
    source = inspect.getsource(cls) 
    globs = {} 
    globs.update(sys.modules[cls.__module__].__dict__) 
    globs.update(new_globals) 
    exec source in globs 
    return globs[cls.__name__] 


# Check that it works... 
import test 

NewFoo = copy_class(test.Foo, {'FOO': 2}) 

print NewFoo().method() 
NewFoo().subclass_method() 

print test.Foo().method() 
test.Foo().subclass_method() 

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

Теперь «преимущества» ...

  1. Если глобальный запрашивается функцией, но не входит в комплект, это будет использовать глобальный от старого пространства имен. Если это поведение нежелательно (т. Е. Вы предпочитаете NameError), вы можете легко изменить функцию, чтобы удалить ее.
  2. «Копия» не наследуется от оригинала. В большинстве случаев, это, вероятно, не имеет значения, но это немного странно иметь копию чего-то унаследовать от оригинала ...

Некоторые люди могли бы увидеть exec здесь и сразу думаю " О нет! exec!?!?! Мир вот-вот закончится !!! ». Фрэнки, это хороший ответ по умолчанию. Тем не менее, я утверждаю, что если вы копируете функцию, которую планируете использовать позже в коде, она не более безопасна, чем использование exec (ведь код функции уже выполнен).

Смежные вопросы