Ваш вопрос интересный, но запутанный.
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'
, не '__main__:t.TestFunc'
как это «должно» быть.
Секретный шаг, на котором это определено, находится в функции get_callable_name()
, как указано энтропия.
Поскольку f.self
является t
и X
имеет имя (TestFunc), но не является классом типа type
(поскольку t
является экземпляром),
инструкция return '%s.%s' % (f_self.__class__.__name__, X.__name__)
выполняется.
Но вы ошибаетесь поставить выражение f_self.__class__.__name
: это имя класса t
, а не имя самого t
.
.
Проблема заключается в том, что, вряд ли к классу (то есть атрибут __name__
), ничего не предназначено на языке Python предоставить имя экземпляра по требованию: экземпляр не имеет такой же атрибут __name__
как класс, который дал бы имя экземпляра.
Таким образом, будучи неспокойным для его получения, необходимо использовать своего рода шунтирование.
Каждый раз, когда требуется имя без ссылки, байпас должен искать среди всех имен пространства имен и проверять соответствующий объект на соответствующий объект.
Вот что делает функция get__callable_name()
от энтропия.
.
Эта функция работает.
Но я хочу подчеркнуть, что это всего лишь сложный обход, который не имеет реального фундамента.
Я имею в виду, что имя t.TestFunc
для метода - иллюзия. Есть тонкость: нет метода, принадлежащего экземпляру. Это кажется странным притворством, но я уверен, что это правда.
Тот факт, что мы называем метод благодаря выражению типа t.TestFunc
, приводит к выводу, что TestFunc
принадлежит экземпляру. В действительности это принадлежит классу, и Python переходит от экземпляра к его классу, чтобы найти метод.
Я ничего не придумывал, я прочитал:
Экземпляр класса имеет пространство имен, выполненный в виде словаря, который является первое место, в котором атрибут ссылки ищутся. Когда атрибут не найден там, и класс экземпляра имеет атрибут этим именем, поиск продолжается с атрибутами класса .Если обнаружен атрибут класса, который является определяемым пользователем 0 функциональным объектом или несвязанным определяемым пользователем объектом метода, ассоциированным классом является класс (называет его C) экземпляра, для которого была инициирована ссылка на атрибут или одна из ее оснований, это , преобразованный в связанный пользовательский объект метода, чей атрибут im_class является C и чей im_self является экземпляром.
http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes
Но хорошо, это другая история, на которой я буду оспаривать, я думаю, и я не ве нет времени, чтобы заниматься этим.
Просто проверьте следующий пункт:
несмотря на то, что getattr(t,"TestFunc")
дает:
<bound method Test.TestFunc of <__main__.Test instance at 0x011D8DC8>>
метод TestFunc не в пространстве имен t
: результат t.__dict__
является { }
!
Я просто хотел указать на это, потому что функция get_callable_name()
воспроизводит и имитирует кажущееся поведение и реализацию Python.
Однако реальное поведение и реализация под капотом различны.
.
В следующем коде, я получаю хороший результат, используя isntruction
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
результат
t == <__main__.Test instance at 0x011DF5A8>
t.TestFunc == <bound method Test.TestFunc of <__main__.Test instance at 0x011DF5A8>>
getattr(t,'TestFunc') == <bound method Test.TestFunc of <__main__.Test instance at 0x011DF5A8>>
Trying to obtain reference of t.TestFunc
----------------------------------------
- REF = obj_to_ref(t.TestFunc) done
- obj arriving in obj_to_ref :
<bound method Test.TestFunc of <__main__.Test instance at 0x011DF5A8>>
- inside get_callable_name()
object X arriving in get_callable_name() :
<bound method Test.TestFunc of <__main__.Test instance at 0x011DF5A8>>
X.__call__ == <method-wrapper '__call__' of instancemethod object at 0x011DB990>
X.__name__ == TestFunc
X.__self__== X.im_self == <__main__.Test instance at 0x011DF5A8>
isinstance(<__main__.Test instance at 0x011DF5A8>, type) is False
f_self.__class__ == __main__.Test
f_self.__class__.__name__ == Test
- REF obtained: '__main__:t.TestFunc'
Verifying what is ref_to_obj(REF)
---------------------------------
- obj2 = ref_to_obj(REF) done
- ref arriving in ref_to_obj == '__main__:t.TestFunc'
we start with dictionary obj == <module '__main__' (built-in)>
object of name t searched in <module '__main__' (built-in)>
got obj == <__main__.Test instance at 0x011DF5A8>
object of name TestFunc searched in <__main__.Test instance at 0x011DF5A8>
got obj == <bound method Test.TestFunc of <__main__.Test instance at 0x011DF5A8>>
- object obtained : <bound method Test.TestFunc of <__main__.Test instance at 0x011DF5A8>>
>>>
Каков фактический прецедент? Для чего вы его используете? Что касается фактической реконструкции: вы можете проверить 'eval ('t.TestFunc')' или 'ref_to_obj ('__ main __: t.TestFunc')' – JCash
Здравствуйте. Что должно делать строка '' для имени в modulename.split ('.') [1:] + rest.split ('.'): ''? В вашем коде '' modulename.split ('.') [1:] '' дает '' [] '' – eyquem
Проблема в 'get_callable_name', я думаю. 'get_callable_name (t.TestFunc)' дает '' Test.TestFunc''. Это явно неправильно, поскольку похоже, что это указывает на метод класса, а не на связанный метод. – entropy