说我有以下内容:
def func():
print 'this is a function and not a method!!!'
class Test:
def TestFunc(self):
print 'this is Test::TestFunc method'
我有以下功能(取自https://bitbucket.org/agronholm/apscheduler/src/d2f00d9ac019/apscheduler/util.py):
def get_callable_name(func):
"""
Returns the best available display name for the given function/callable.
"""
f_self = getattr(func, '__self__', None) or getattr(func, 'im_self', None)
if f_self and hasattr(func, '__name__'):
if isinstance(f_self, type):
# class method
clsname = getattr(f_self, '__qualname__', None) or f_self.__name__
return '%s.%s' % (clsname, func.__name__)
# bound method
return '%s.%s' % (f_self.__class__.__name__, func.__name__)
if hasattr(func, '__call__'):
if hasattr(func, '__name__'):
# function, unbound method or a class with a __call__ method
return func.__name__
# instance of a class with a __call__ method
return func.__class__.__name__
raise TypeError('Unable to determine a name for %s -- '
'maybe it is not a callable?' % repr(func))
def obj_to_ref(obj):
"""
Returns the path to the given object.
"""
ref = '%s:%s' % (obj.__module__, get_callable_name(obj))
try:
obj2 = ref_to_obj(ref)
if obj != obj2:
raise ValueError
except Exception:
raise ValueError('Cannot determine the reference to %s' % repr(obj))
return ref
def ref_to_obj(ref):
"""
Returns the object pointed to by ``ref``.
"""
if not isinstance(ref, basestring):
raise TypeError('References must be strings')
if not ':' in ref:
raise ValueError('Invalid reference')
modulename, rest = ref.split(':', 1)
try:
obj = __import__(modulename)
except ImportError:
raise LookupError('Error resolving reference %s: '
'could not import module' % ref)
try:
for name in modulename.split('.')[1:] + rest.split('.'):
obj = getattr(obj, name)
return obj
except Exception:
raise LookupError('Error resolving reference %s: '
'error looking up object' % ref)
上述函数 - obj_to_ref
返回对给定函数对象的文本引用,ref_to_obj
返回给定文本引用的对象。例如,让我们尝试func
函数。
>>>
>>> func
<function func at 0xb7704924>
>>>
>>> obj_to_ref(func)
'__main__:func'
>>>
>>> ref_to_obj('__main__:func')
<function func at 0xb7704924>
>>>
func
功能正常运行。但是当试图在class Test
的实例上使用这些函数时,它无法获得文本引用。
>>>
>>> t = Test()
>>>
>>> t
<__main__.Test instance at 0xb771b28c>
>>>
>>> t.TestFunc
<bound method Test.TestFunc of <__main__.Test instance at 0xb771b28c>>
>>>
>>>
>>> obj_to_ref(t.TestFunc)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in obj_to_ref
ValueError: Cannot determine the reference to <bound method Test.TestFunc of <__main__.Test instance at 0xb771b28c>>
>>>
>>>
给定输入obj_to_ref
的{{1}}函数以t.TestFunc
作为文本表示,但不能使用相同的文本生成对象。
问题:
在__main__:Test.TestFunc
中是否存在可以表示像
Python
在字符串中并从字符串重构对象?
如果我们将地址>>> t.TestFunc
<bound method Test.TestFunc of <__main__.Test instance at 0xb771b28c>>
>>>
保存为字符串的一部分并通过取消引用此地址来重新生成对象,是否可以实现?!
答案 0 :(得分:1)
正如我在上面的评论中所说,问题出在get_callable_name
。 get_callable_name(t.TestFunc)
产生'Test.TestFunc'
这显然是错误的。它应该是't.TestFunc'。我添加了variable_name_in_module
并在get_callable_name
中使用了该代码,现在代码正常运行。底部的检查返回True
。但是,variable_name_in_module
是非常hackish,我无法找到一种干净利落的方式。
如果你只需要这个小东西,那么这应该没问题,但要注意variable_name_in_module
每次调用get_callable_name
都会产生一个N字典查找,其中N是模块中变量的数量
代码如下:
def variable_name_in_module(module, var):
for name in dir(module):
if getattr(module, name) == var:
return name
def get_callable_name(func):
"""
Returns the best available display name for the given function/callable.
"""
f_self = getattr(func, '__self__', None) or getattr(func, 'im_self', None)
if f_self and hasattr(func, '__name__'):
if isinstance(f_self, type):
# class method
clsname = getattr(f_self, '__qualname__', None) or f_self.__name__
return '%s.%s' % (clsname, func.__name__)
# bound method
return '%s.%s' % (variable_name_in_module(__import__(f_self.__module__), f_self), func.__name__)
if hasattr(func, '__call__'):
if hasattr(func, '__name__'):
# function, unbound method or a class with a __call__ method
return func.__name__
# instance of a class with a __call__ method
return func.__class__.__name__
raise TypeError('Unable to determine a name for %s -- '
'maybe it is not a callable?' % repr(func))
def obj_to_ref(obj):
"""
Returns the path to the given object.
"""
ref = '%s:%s' % (obj.__module__, get_callable_name(obj))
try:
obj2 = ref_to_obj(ref)
if obj != obj2:
raise ValueError
except Exception:
raise ValueError('Cannot determine the reference to %s' % repr(obj))
return ref
def ref_to_obj(ref):
"""
Returns the object pointed to by ``ref``.
"""
if not isinstance(ref, basestring):
raise TypeError('References must be strings')
if not ':' in ref:
raise ValueError('Invalid reference')
modulename, rest = ref.split(':', 1)
try:
obj = __import__(modulename)
except ImportError:
raise LookupError('Error resolving reference %s: '
'could not import module' % ref)
try:
for name in modulename.split('.')[1:] + rest.split('.'):
obj = getattr(obj, name)
return obj
except Exception:
raise LookupError('Error resolving reference %s: '
'error looking up object' % ref)
class Test:
def TestFunc(self):
print "test"
t = Test()
print t.TestFunc == ref_to_obj(obj_to_ref(t.TestFunc))
编辑:PS:variable_name_in_module
如果找不到任何内容可能会抛出异常,但我不知道会发生什么。
答案 1 :(得分:1)
你的问题很有趣但很纠结。
1)您不应该致电func
参数get_callable_name(func)
在我的回答中,我将其替换为X
。
2)您将部分代码放在错误的位置。
try:
obj2 = ref_to_obj(ref)
print 'obj != obj2 : ',obj != obj2
if obj != obj2:
raise ValueError
except Exception:
raise ValueError('Cannot determine the reference to %s' % repr(obj))
return ref
在obj_to_ref()
在我的回答中,我把它移到了这个功能之外。
3)代码问题的明显原因是对象t.TestFunc
(在我的代码中传递给参数X
)获得的引用是'__main__:Test.TestFunc'
,而不是{{1因为它“应该”。
决定这一点的秘密步骤是在函数'__main__:t.TestFunc'
中,如 entropy 所述。
由于get_callable_name()
为f.self
且t
具有名称(TestFunc),但不是X
类型的类(因为type
是实例),所以/>
执行指令t
。
但是你把表达式return '%s.%s' % (f_self.__class__.__name__, X.__name__)
放错了:它是f_self.__class__.__name
类的名称,而不是t
本身的名称。
问题在于,不太可能是类(具有属性t
),Python语言中没有任何内容可以按需提供实例的名称:实例具有不同的属性__name__
作为一个类,它将给出实例的名称。
因此,如果不熟悉,必须采取一种旁路措施
每次需要一个未引用的名称时,旁路就是搜索命名空间的所有名称,并根据相关对象测试相应的对象。
这就是熵的函数__name__
。
使用此功能,它可以工作。
但我想强调,这只是一个棘手的绕过而没有真正的基础
我的意思是该方法的名称get__callable_name()
是一种幻觉。有一个微妙之处:没有属于实例的方法。这似乎是一个奇怪的预设,但我确信这是事实
我们通过类似t.TestFunc
这样的表达式调用方法的事实导致相信t.TestFunc
属于实例。实际上它属于类,Python从实例到它的类来查找方法。
我没有发明任何东西,我已经读过了:
一个类实例有一个名称实现为字典的名称空间 搜索属性引用的第一个位置。当一个 在那里找不到属性,并且实例的类有一个 通过该名称的属性,搜索继续该类 属性。如果找到属性是用户定义的类属性 函数对象或未绑定的用户定义的方法对象 关联类是实例的类(称之为C) 属性引用已启动或其基础之一,它是 转换为绑定的用户定义的方法对象,其im_class attribute是C,其im_self属性是实例。
http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes
但是,我想,这是另一个我将受到争议的故事,我没有时间参与其中。
只需验证以下几点:
尽管TestFunc
给出了这样的事实:
getattr(t,"TestFunc")
TestFunc方法不在<bound method Test.TestFunc of <__main__.Test instance at 0x011D8DC8>>
的命名空间中:
t
的结果是t.__dict__
!
我只想指出它,因为函数{ }
只能再现和模仿Python的明显行为和实现。
然而,引擎盖下的真实行为和实施是不同的。
在下面的代码中,我通过使用isntruction
获得了良好的结果
get_callable_name()
而非
return '%s.%s' % ('t', X.__name__)
或
return '%s.%s' % (f_self.__class__.__name__, func.__name__)
因为它基本上是函数return '%s.%s' % (variable_name_in_module(__import__(f_self.__module__), f_self),
func.__name__)
(它不使用正常过程,它使用狡猾)
get_callanle_name()
结果
def get_callable_name(X):
"""
Returns the best available display name for the given function/callable.
"""
print '- inside get_callable_name()'
print ' object X arriving in get_callable_name() :\n ',X
f_self = getattr(X, '__self__', None) or getattr(X, 'im_self', None)
print ' X.__call__ ==',X.__call__
print ' X.__name__ ==',X.__name__
print '\n X.__self__== X.im_self ==',f_self
print ' isinstance(%r, type) is %r' % (f_self,isinstance(f_self, type))
if f_self and hasattr(X, '__name__'): # it is a method
if isinstance(f_self, type):
# class method
clsname = getattr(f_self, '__qualname__', None) or f_self.__name__
return '%s.%s' % (clsname, X.__name__)
# bound method
print '\n f_self.__class__ ==',f_self.__class__
print ' f_self.__class__.__name__ ==',f_self.__class__.__name__
return '%s.%s' % ('t', X.__name__)
if hasattr(X, '__call__'):
if hasattr(X, '__name__'):
# function, unbound method or a class with a __call__ method
return X.__name__
# instance of a class with a __call__ method
return X.__class__.__name__
raise TypeError('Unable to determine a name for %s -- '
'maybe it is not a callable?' % repr(X))
def obj_to_ref(obj):
"""
Returns the path to the given object.
"""
print '- obj arriving in obj_to_ref :\n %r' % obj
ref = '%s:%s' % (obj.__module__, get_callable_name(obj))
return ref
def ref_to_obj(ref):
"""
Returns the object pointed to by ``ref``.
"""
print '- ref arriving in ref_to_obj == %r' % ref
if not isinstance(ref, basestring):
raise TypeError('References must be strings')
if not ':' in ref:
raise ValueError('Invalid reference')
modulename, rest = ref.split(':', 1)
try:
obj = __import__(modulename)
except ImportError:
raise LookupError('Error resolving reference %s: '
'could not import module' % ref)
print ' we start with dictionary obj == ',obj
try:
for name in modulename.split('.')[1:] + rest.split('.'):
print ' object of name ',name,' searched in',obj
obj = getattr(obj, name)
print ' got obj ==',obj
return obj
except Exception:
raise LookupError('Error resolving reference %s: '
'error looking up object' % ref)
class Test:
def TestFunc(self):
print 'this is Test::TestFunc method'
t = Test()
print 't ==',t
print '\nt.TestFunc ==',t.TestFunc
print "getattr(t,'TestFunc') ==",getattr(t,'TestFunc')
print ('\nTrying to obtain reference of t.TestFunc\n'
'----------------------------------------')
print '- REF = obj_to_ref(t.TestFunc) done'
REF = obj_to_ref(t.TestFunc)
print '\n- REF obtained: %r' % REF
print ("\n\nVerifying what is ref_to_obj(REF)\n"
"---------------------------------")
try:
print '- obj2 = ref_to_obj(REF) done'
obj2 = ref_to_obj(REF)
if obj2 != t.TestFunc:
raise ValueError
except Exception:
raise ValueError('Cannot determine the object of reference %s' % REF)
print '\n- object obtained : ',obj2