Я не знаю о вас, но я вообще не люблю использовать 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()
Это имеет некоторые, возможно, желаемые свойства и нежелательна ... Во-первых, он работает только на проверенных классах. Это почти все, что определено пользователем, поэтому, вероятно, не слишком ограничительный ... Это также может быть немного медленнее, чем другие решения, которые не связаны с повторным анализом исходной строки. Но опять-таки это не похоже на это. должен быть выполнен также , так что это, вероятно, хорошо.
Теперь «преимущества» ...
- Если глобальный запрашивается функцией, но не входит в комплект, это будет использовать глобальный от старого пространства имен. Если это поведение нежелательно (т. Е. Вы предпочитаете
NameError
), вы можете легко изменить функцию, чтобы удалить ее.
- «Копия» не наследуется от оригинала. В большинстве случаев, это, вероятно, не имеет значения, но это немного странно иметь копию чего-то унаследовать от оригинала ...
Некоторые люди могли бы увидеть exec
здесь и сразу думаю " О нет! exec
!?!?! Мир вот-вот закончится !!! ». Фрэнки, это хороший ответ по умолчанию. Тем не менее, я утверждаю, что если вы копируете функцию, которую планируете использовать позже в коде, она не более безопасна, чем использование exec
(ведь код функции уже выполнен).
Я не вижу несвязанных методов в своем dict .... Должен ли я просто копировать элементы FunctionType «dict», как обычные функции? –
@ Ярослав Булатов: Да, поскольку они являются регулярными функциями. – user2357112