2012-08-04 86 views

回答

1

你不能,因爲可揀對象的類定義必須駐留在導入的模塊的作用域中。只要把你的課程放在模塊範圍內,你就可以走了。

這就是說,在Python中很少有一些黑客無法實現機器內部(在這種情況下是sys.modules),但我不會建議這樣做。

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_codefunc功能的代碼,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函數ns至新類:

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 
+0

有趣......但我不清楚這是如何用來醃製函數中定義的類的實例 - 也不能醃製代碼對象。 – martineau 2012-08-04 18:42:58

1

您可以解決泡菜的要求,即類定義由包括類定義爲醃漬實例數據的字符串和exec() uting它自己通過增加取儲存時要導入的__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') 

顯然,這是低效的,包括類定義字符串醃每一個類的實例,使冗餘可以使其不切實際的,這取決於涉及的類實例的數量。

1

這樣做有些困難,因爲Pickle默認使用用戶定義類中的對象的方式是創建類的新實例 - 使用對象的__class__.__name__屬性在對象的原始模塊中檢索其類型。這意味着:pickling和unpickling只對在定義的模塊中定義明確名稱的類有效(默認情況下)。

當在函數內定義一個類時,usulay將不會有一個模塊級(即全局)變量,它保存在該函數內創建的每個類的名稱。

的泡菜和npickle的行爲可以通過對類__getstate____setstate__方法進行自定義 - 檢查docs - 但即使是他們,這樣做是正確的動態類可能會非常棘手,但我設法創造的工作實現它爲另一個SO問題 - 在這裏檢查我的答案: Pickle a dynamically parameterized sub-class

相關問題