假设我在模块中有这个片段
def func(params):
class MyClass(object):
pass
如何挑选MyClass类的实例?
答案 0 :(得分:1)
您不能,因为可选对象的类定义必须位于导入模块的范围内。只需将您的课程放在模块范围内,就可以了。
也就是说,在Python中,通过对机器内部(本例中为sys.modules)进行一些黑客攻击是无法实现的,但我不建议这样做。
答案 1 :(得分:1)
MyClass
定义是func
函数的局部变量。您无法直接创建它的实例,但您可以将其函数映射到新类,然后使用新类,因为它是原始类。这是一个例子:
def func(params):
class MyClass(object):
some_param = 100
def __init__(self, *args):
print "args:", args
def blabla(self):
self.x = 123
print self.some_param
def getme(self):
print self.x
func.func_code
是func
函数的代码,func.func_code.co_consts[2]
包含MyClass
定义的字节码:
In : func.func_code.co_consts
Out:
(None,
'MyClass',
<code object MyClass at 0x164dcb0, file "<ipython-input-35-f53bebe124be>", line 2>)
所以我们需要MyClass
函数的字节码:
In : eval(func.func_code.co_consts[2])
Out:
{'blabla': <function blabla at 0x24689b0>,
'__module__': '__main__',
'getme': <function getme at 0x2468938>,
'some_param': 100,
'__init__': <function __init__ at 0x219e398>}
最后我们创建了一个带有元类的新类,它将MyClass函数分配给新类:
def map_functions(name, bases, dict):
dict.update(eval(func.func_code.co_consts[2]))
return type(name, bases, dict)
class NewMyClass(object):
__metaclass__ = map_functions
n = NewMyClass(1, 2, 3, 4, 5)
>> args: (1, 2, 3, 4, 5)
n.blabla()
>> 100
n.getme()
>> 123
答案 2 :(得分:1)
您可以通过将类定义作为字符串包含在实例的pickle数据中来解决可以导入类定义的pickle要求,并通过添加exec()
方法进行unpickling时自己__reduce__()
自己使用它将类定义传递给可调用的。这是一个简单的例子来说明我的意思:
from textwrap import dedent
# Scaffolding
definition = dedent('''
class MyClass(object):
def __init__(self, attribute):
self.attribute = attribute
def __repr__(self):
return '{}({!r})'.format(self.__class__.__name__, self.attribute)
def __reduce__(self):
return instantiator, (definition, self.attribute)
''')
def instantiator(class_def, init_arg):
""" Create class and return an instance of it. """
exec(class_def)
TheClass = locals()['MyClass']
return TheClass(init_arg)
# Sample usage
import pickle
from io import BytesIO
stream = BytesIO() # use a memory-backed file for testing
obj = instantiator(definition, 'Foo') # create instance of class from definition
print('obj: {}'.format(obj))
pickle.dump(obj, stream)
stream.seek(0) # rewind
obj2 = pickle.load(stream)
print('obj2: {}'.format(obj2))
输出:
obj: MyClass('Foo')
obj2: MyClass('Foo')
显然,将每个类实例选中的类定义字符串包含在内是没有效率的,因此冗余可能会使其不切实际,具体取决于所涉及的类实例的数量。
答案 3 :(得分:1)
这有点难以做到,因为Pickle默认使用来自用户定义类的对象的方式是创建类的新实例 - 使用对象的__class__.__name__
属性在对象的原始模块中检索其类型。这意味着:对于在定义模块中具有明确定义名称的类,pickling和unpickling仅适用于(默认情况下)。
当一个人在一个函数中定义一个类时,usulay就不会有一个模块级别(即全局)变量,它保存在函数内部创建的每个类的名称。
pickle和npickle的行为可以通过类上的__getstate__
和__setstate__
方法进行自定义 - 检查docs
- 但即便如此,为动态类做正确的行为也可以棘手,但我设法为另一个SO创建了它的工作实现问题 - 检查我的答案:
Pickle a dynamically parameterized sub-class