如何深拷贝Python class?
How to make deep copy of Python class?
我想复制 class,同时更新其所有方法以引用一组新的 __globals__
我在想类似下面的事情,但是与 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)
__dict__
值是函数,而不是未绑定的方法。未绑定的方法对象仅在属性访问时创建。如果您 在 __dict__
中看到未绑定的方法对象,那么在此函数到达它之前,您的 class 对象发生了一些奇怪的事情。
我不了解你,但我通常不喜欢将 types
用于类型检查以外的任何事情(我不经常这样做 ;-)。我宁愿 inspect
...
我必须在这段代码的开头说我希望你有一个很好的理由想要这样做;-) - 对我来说,它似乎只是subclassing和覆盖class 属性应该更优雅地完成工作......但是,如果你真的想复制一个 class -- 为什么不在新的命名空间中再次执行它的源代码?
我整理了以下简单模块:
# 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()
这有一些可能需要的属性和不需要的...首先,它只适用于可检查的 classes。这几乎是用户定义的任何东西,所以可能不会 太 限制......它也可能比其他不涉及重新解析源字符串的解决方案慢一点 - 但同样,这似乎不应该太经常执行,所以这可能没问题。
现在 "advantages"...
- 如果函数请求全局但未提供,这将使用旧命名空间中的全局。如果这种行为是不可取的(即你宁愿有
NameError
),你可以很容易地修改函数来删除它。
- "copy"不继承原版。对于大多数用途来说,这可能并不重要,但是让某些东西的副本继承自原始版本有点奇怪...
有些人看到这里的exec
可能会立即想到"Oh no! exec
!?!?! The world is about to end!!!"。弗兰基,这是一个很好的默认响应。但是,我认为,如果您正在复制一个计划稍后在代码中使用的函数,那么它并不比使用 exec
更安全(毕竟,该函数的代码已经被执行过)。
我想复制 class,同时更新其所有方法以引用一组新的 __globals__
我在想类似下面的事情,但是与 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)
__dict__
值是函数,而不是未绑定的方法。未绑定的方法对象仅在属性访问时创建。如果您 在 __dict__
中看到未绑定的方法对象,那么在此函数到达它之前,您的 class 对象发生了一些奇怪的事情。
我不了解你,但我通常不喜欢将 types
用于类型检查以外的任何事情(我不经常这样做 ;-)。我宁愿 inspect
...
我必须在这段代码的开头说我希望你有一个很好的理由想要这样做;-) - 对我来说,它似乎只是subclassing和覆盖class 属性应该更优雅地完成工作......但是,如果你真的想复制一个 class -- 为什么不在新的命名空间中再次执行它的源代码?
我整理了以下简单模块:
# 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()
这有一些可能需要的属性和不需要的...首先,它只适用于可检查的 classes。这几乎是用户定义的任何东西,所以可能不会 太 限制......它也可能比其他不涉及重新解析源字符串的解决方案慢一点 - 但同样,这似乎不应该太经常执行,所以这可能没问题。
现在 "advantages"...
- 如果函数请求全局但未提供,这将使用旧命名空间中的全局。如果这种行为是不可取的(即你宁愿有
NameError
),你可以很容易地修改函数来删除它。 - "copy"不继承原版。对于大多数用途来说,这可能并不重要,但是让某些东西的副本继承自原始版本有点奇怪...
有些人看到这里的exec
可能会立即想到"Oh no! exec
!?!?! The world is about to end!!!"。弗兰基,这是一个很好的默认响应。但是,我认为,如果您正在复制一个计划稍后在代码中使用的函数,那么它并不比使用 exec
更安全(毕竟,该函数的代码已经被执行过)。