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()関数を使用しても同じ結果が得られます。