1

私が次を持っているとしましょう:

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関数はt.TestFuncテキスト__main__:Test.TestFunc表現として作成されますが、同じテキストを使用してオブジェクトを生成することはできません。

質問:

Python次のようなオブジェクトを表現できる方法はありますか

>>> t.TestFunc
<bound method Test.TestFunc of <__main__.Test instance at 0xb771b28c>>
>>> 

文字列で、文字列からオブジェクトを再構築しますか?

0xb771b28cアドレスを文字列の一部として保存し、このアドレスを逆参照してオブジェクトを再生成することは可能でしょうか?!

4

2 に答える 2

3

上記のコメントで述べたように、問題はにありget_callable_nameます。明らかに間違っているget_callable_name(t.TestFunc)収量。'Test.TestFunc''t.TestFunc'である必要があります。私はそれを追加variable_name_in_moduleして使用しましたがget_callable_name、コードは機能します。下部のチェックはを返しますTrue。しかし、variable_name_in_moduleそれは非常にハックであり、私はこれをきれいに行う方法を見つけることができませんでした。

小さいものにのみこれが必要な場合は、これで問題ありませんがvariable_name_in_module、呼び出しごとにNディクショナリルックアップが発生することに注意してくださいget_callable_name。ここで、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何も見つからない場合は、おそらく例外をスローする必要がありますが、それがどのように発生するかはわかりません。

于 2013-02-19T23:12:09.153 に答える
2

あなたの質問は興味深いですが、絡み合っています。

func1)のパラメータを呼び出すべきではありません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()によって言われる関数にあります。は名前(TestFunc)を持っていますが、タイプのクラスではない ため(インスタンスであるため)、 命令が実行されます。
f.selftXtypet
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はインスタンスからそのクラスに移動してメソッドを見つけます。

私は何も発明していません、私はそれを読みました:

クラスインスタンスには、属性参照が検索される最初の場所であるディクショナリとして実装された名前空間があります。そこに属性が見つからず、インスタンスのクラスにその名前の属性がある場合、検索はクラス属性で続行されます。ユーザー定義関数オブジェクトまたはバインドされていないユーザー定義メソッドオブジェクトであるクラス属性が見つかった場合、その関連クラスは、属性参照が開始されたインスタンスまたはそのベースの1つのクラス(Cと呼びます)です。 im_class属性がCで、im_self属性がインスタンスであるバインドされたユーザー定義メソッドオブジェクトに変換されます。

http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes

しかし、まあ、それは私が論争される別の話だと私は思います、そして私はそれに従事する時間がありません。

次の点を確認してください。: メソッドTestFuncが次の名前空間にない
という事実にもかかわらず:結果getattr(t,"TestFunc")
<bound method Test.TestFunc of <__main__.Test instance at 0x011D8DC8>>
tt.__dict__{ }

get_callable_name()この関数はPythonの見かけの動作と実装のみを再現および模倣しているため、指摘したいと思います。
ただし、実際の動作と内部での実装は異なります。


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__)
本質的に関数を実行するためにisntructionを使用することで、良い結果が得られます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>>
>>>
于 2013-02-19T23:28:38.683 に答える