3

言ってやるが、私は次のようにclass呼ばれるTestmethodstart

>>> class Test:
...     def __init__(self, *args, **kwargs):
...         pass
...     def start(self):
...         pass
... 

今、私はスタンドアロンの独立したfunctionと呼ばれるfunc

>>> def func():
...     print 'this is a func and not a method!!!'
... 
>>> 

[1]さて、にt.start属するのはmethodinstance of __main__.Test0xb769678c

>>> t = Test()
>>> t.start
<bound method Test.start of <__main__.Test instance at 0xb769678c>>
>>> 

[2] funcfunctionその場所に属する0xb767ec6c

>>> func
<function func at 0xb767ec6c>
>>> 

これで、組み込みのを使用して__module__からt.startを抽出できます。当然のことながら、同じすなわちに属しますfunc__module__funct.startmodule__main__

>>> func.__module__
'__main__'
>>> t.__module__
'__main__'
>>> 

[3]では、変数に格納__module__しましょうt.startobj

>>> obj = __import__(t.start.__module__)
>>> obj
<module '__main__' (built-in)>
>>> 

ここで、次のように関数のハンドルgetattr()を取得するために使用します。の出力はto[2]です。func<function func at 0xb767ec6c>funcgetattr()identical

>>> print getattr(obj, 'func')
<function func at 0xb767ec6c>
>>> 
>>> print getattr(__import__('__main__'), 'func')
<function func at 0xb767ec6c>
>>> 

質問:

getattr()モジュール名[3]を使用して、 Test.start[1]のハンドルを取得するにはどうすればよいですか。<bound method Test.start of <__main__.Test instance at 0xb769678c>>

getattr()使ってみると't.start'次のようになりましたTraceback

>>> print getattr(obj, 'Test.start')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'Test.start'
>>> 
>>> 
>>> print getattr(__import__('__main__'), 'Test.start')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'Test.start'
>>> 

つまり、2つのデータがあります。彼らです

  1. __import__('__main__')
  2. 刺す'Test.start'

さて、どうすればt.start(ここに注意してinstanceください)のハンドルを取得できますか?<bound method Test.start of <__main__.Test instance at 0xb769678c>>

4

3 に答える 3

3

私はあなたの質問を理解しているかどうかわかりませんが、これはあなたが望むことをしていると思います:

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

def func():
    print('this is a func and not a method!!!')

t = Test()

module = __import__(t.start.__module__)

print(vars(module)['Test'].start)
print(vars(module)['func'])
print(vars(module)['t'].start)

(Python 3)出力:

<function Test.start at 0x00E52460>
<function func at 0x00E524F0>
<bound method Test.start of <__main__.Test object at 0x008DF670>>
于 2013-02-12T03:49:20.827 に答える
1
obj = __import__(t.start.__module__)    

test_class = getattr(obj, 'Test')

print getattr(test_class, 'start')

モジュールから直接必要かどうかはわかりません(またはそれが可能である場合でも):/

次のものも使用できます。

obj = __import__(t.start.__module__)

print obj.__dict__["Test"].__dict__["start"]

しかし、あなたはそう求めましgetattr()た...

于 2013-02-12T00:57:16.147 に答える
0

getattr()関数obj = __import__(t.start.__module__)
のおかげで、モジュールの名前空間内のオブジェクトをモジュールの属性として取得できるようにするために、メインモジュールの名前を保持するのはなぜだと思いますか。

私はあなたがこのトリックをする必要がないことをあなたに知らせます。 globals()は、メインスペースのグローバル名前空間を表す辞書です。次に、たとえば、オブジェクトfuncglobals()["func"]を取得するように記述できます。

また、その名前のおかげで、オブジェクトNの名前空間でオブジェクトxyzgetattr(N,"xyz")を取得する以外の方法があることもお知らせします。これは、次の方法 によるものです。オブジェクトNの名前空間へのアクセスを提供します。xyz__dict__N.__dict__


あなたの問題は、エラーを引き起こしたPythonの微妙なところにあるのではないかと思います。

あなたの質問では、あなたが書いた場所とあなたが書いt.__module__た別の場所でt.start.__module__
2つのケースの場合、結果は同じで次のようになります。"__main__"

ただし、
1)tには名前の属性がありません__module__
2)tには名前の属性さえありませんstart
印刷t.__dict__すると、結果が{ }

startは、実際にはTestの名前空間に属しているため、実際にはインスタンスtの名前空間に属していません。

次のコードは、これらの肯定を証明します。

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

y = Test()
y.ku = 102

print 'y.__dict__',y.__dict__
print 'Test.__dict__',Test.__dict__

結果

y.__dict__ {'ku': 102}
Test.__dict__ {'start': <function start at 0x011E11B0>,
'__module__': '__main__',
'__doc__': None,
'__init__': <function __init__ at 0x011E1170>}

t.__module__ とにかく表現と答えを与える理由はt.start.__module__ 、この引用によって説明されています:

クラスインスタンスには、属性参照が検索される最初の場所であるディクショナリとして実装された名前空間があります。
そこに属性が見つからず、インスタンスのクラスにその名前の属性がある場合、検索はクラス属性で続行されます。

http://docs.python.org/2/reference/datamodel.html#index-55

したがって、
1)tには名前の属性がない__module__ため、Pythonはtのクラスでそれを検索します。2
tには名前の属性がなく、Pythonはtstartのクラスでそれを検索します。

そうですね、Pythonはtt.__module__のクラスに移動して、の値を見つけますt.start.__module__
。上記の引用で説明されているこのメカニズムは、次のコードで確認できます。

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

t = Test()

print 'getattr(t,"start")'
print getattr(t,"start")

# result is
getattr(t,"start")
<bound method Test.start of <__main__.Test instance at 0x011DF288>>

つまり、Pythonは、名前がt.start ではなくTest.startであるtの属性に答えます。"start"

これにより、という事実から、t.startt.start.__module__はモジュールの名前空間に属している"__main__"と思われるかもしれません。 したがって、オブジェクトstartを取得するために次のようなものを記述できるはずです。getattr(obj,"func")

しかし、それは誤りです。Testの名前空間にあるため、モジュールのグローバル名前空間=名前空間にメソッドstart
(私はMETHODを記述します)を 見つけることができません。メソッドとして、インスタンスまたはクラスを介して、あるいはクラス自体を介してそれを達成する必要があります。


もう一つ。メソッドt.startは、それとは異なる何かであり、モジュールの名前空間にあるFUNCTIONに基づいている
と私は信じているので、私は正確に:METHODを作成しました。実際には、メソッドは、インスタンスとこのグローバル名前空間の関数を指すポインターのラッパーです。

それでもメソッドがどのように機能するかを理解していない場合は、実装を見ると問題が明らかになる可能性があります。データ属性ではないインスタンス属性が参照されると、そのクラスが検索されます。名前が関数オブジェクトである有効なクラス属性を示している場合、メソッドオブジェクトは、インスタンスオブジェクトと抽象オブジェクトで一緒に見つかった関数オブジェクトをパック(ポインタ)することによって作成されます。これがメソッドオブジェクトです。メソッドオブジェクトが引数リストで呼び出されると、インスタンスオブジェクトと引数リストから新しい引数リストが作成され、この新しい引数リストで関数オブジェクトが呼び出されます。

http://docs.python.org/2/tutorial/classes.html#method-objects

私が強調したいのは、メソッドが基づいている関数(メソッドではない)がどこかに存在するように見えるということです。

私が信じているのは、この関数がモジュールの名前空間にあり、それが 、バインドされたメソッドとバインドされていないメソッドをローカライズせずに 、 while と give をTest.__dict__["start"]
与える理由です。
<function start at 0x011E40F0>

getattr(Test,"start")
getattr(t,"start")

<unbound method Test.start>
<bound method Test.start of <__main__.Test instance at 0x011DF530>>

したがって、私の意見では、ドキュメントを正しく理解している限り(ちなみに、これらの点を十分に説明していません)、メソッドはラッパーであり、モジュールにある実際の関数に基づいています名前空間、そしてそれが理由t.start.__module__でありTest.start.__module__"__main__"

モジュールの名前空間に、次のように出力したときにモジュールの属性の中に表示されない関数が存在するのは少し奇妙に思えるかもしれませんglobals()

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

def func():
    print 'this is a func and not a method!!!'

t = Test()

print '* globals()["func"]'
print globals()["func"]
print id(globals()["func"])
print "===================================="
print '* Test.__dict__["start"]'
print Test.__dict__["start"]
print id(Test.__dict__["start"])
print '----------------------------------------------'
print '* getattr(Test,"start")'
print getattr(Test,"start")
print id(getattr(Test,"start"))
print '----------------------------------------------'
print '* getattr(t,"start")'
print getattr(t,"start")
print id(getattr(t,"start"))
print "===================================="
print globals()

結果

* globals()["func"]
<function func at 0x011C27B0>
18622384
====================================
* Test.__dict__["start"]
<function start at 0x011DEFB0>
18739120
----------------------------------------------
* getattr(Test,"start")
<unbound method Test.start>
18725304
----------------------------------------------
* getattr(t,"start")
<bound method Test.start of <__main__.Test instance at 0x011DF418>>
18725304

{'__builtins__': <module '__builtin__' (built-in)>,
'__package__': None,
't': <__main__.Test instance at 0x011DF418>,
'func': <function func at 0x011C27B0>,
'Test': <class __main__.Test at 0x011DC538>,
'__name__': '__main__',
'__doc__': None}

しかし、実際にはTest.__dict__["start"]、アドレス18739120がバインドされたメソッドおよびバインドされていないメソッドのアドレス18725304とは異なる関数が表示されます。
さらに、公開されたファクトの全体を説明できる他の説明はわかりません。

実際、割り当てられた名前を受け取らなかった関数がモジュールの名前空間に表示されないという事実には、何も奇妙なことはありません。
これはPythonに必要な内部関数であり、プログラマーが自由に使用できるものではありません。それだけです。


funcに関しては、使用したすべての方法を使用します。

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

def func():
    print 'this is a func and not a method!!!'

t = Test()
print 'func --->',func
print id(func)

print '\nobj = __import__(t.start.__module__)  done\n'
obj = __import__(t.start.__module__)

print '* globals()["func"]'
print globals()["func"]
print id(globals()["func"])
print '* obj.__dict__["func"]'
print obj.__dict__["func"] 
print "* getattr(obj, 'func')"
print getattr(obj, 'func')
print "* getattr(__import__('__main__'), 'func')"
print getattr(__import__('__main__'), 'func')

結果

func ---> <function func at 0x011C2470>
18621552

obj = __import__(t.start.__module__)  done

* globals()["func"]
<function func at 0x011C2470> # <== address in hexadecimal
18621552                      # <== address in decimal
* obj.__dict__["func"]
<function func at 0x011C2470>
* getattr(obj, 'func')
<function func at 0x011C2470>
* getattr(__import__('__main__'), 'func')
<function func at 0x011C2470>

次に、以下を使用してメソッドを分解しますobj

class Test:
    def __init__(self, *args, **kwargs):
        pass
    def start(self):
        pass

print 'Test.start -->',Test.start
print id(Test.start)
print '----------------------------------------------'
print '* Test.__dict__["start"]'
print Test.__dict__["start"]
print id(Test.__dict__["start"])

print '* getattr(Test,"start")'
print getattr(Test,"start")
print id(getattr(Test,"start"))
print '\n'


print 't.start -->',t.start
print id(t.start)
print '----------------------------------------------'
print '* t.__dict__["start"]'
try:
    print t.__dict__["start"]
    print id(t.__dict__["start"])
except KeyError as e:
    print 'KeyError :',e

print '* getattr(t,"start")'
print getattr(t,"start")
print id(getattr(t,"start"))

結果

Test.start --> <unbound method Test.start>
18725264
----------------------------------------------
* Test.__dict__["start"]
<function start at 0x011E40F0>
18759920
* getattr(Test,"start")
<unbound method Test.start>
18725264


t.start --> <bound method Test.start of <__main__.Test instance at 0x011DB940>>
18725264
----------------------------------------------
* t.__dict__["start"]
KeyError : 'start'
* getattr(t,"start")
<bound method Test.start of <__main__.Test instance at 0x011DB940>>
18725264

今までほとんど使っていませんでしgetattr( )た。

これらの結果からgetattr( )、特定の方法で結果が得られることがわかります。属性startは、インスタンスまたはクラスのどちらを介して取得されたかに応じて、バインドまたは非バインドのメソッドとして記述されます。

ただし、__dict__オブジェクトの実際の属性に関する正確な情報のみを提供します。
したがって、startは実際にはインスタンスの名前空間ではなく、クラスの名前空間にのみ存在することがわかります。
名前空間の要素である場合は関数であり、 。Test.__dict__ を介して属性として指定される場合はメソッドであると説明されていますgetattr( )。この最後のケースではアドレスは指定されていません。

vars()関数を使用しても同じ結果が得られます。

于 2013-02-12T04:26:23.937 に答える