2009-07-08 21 views
64

varsayalım myapp/foo.py içerir:Python işlevin modülünü çağıran __name__ alın

def info(msg): 
    caller_name = ???? 
    print '[%s] %s' % (caller_name, msg) 

Ve myapp/bar.py içerir:

import foo 
foo.info('Hello') # => [myapp.bar] Hello 

Ben caller_name çağıran işlevlerin modülün __name__ özniteliği ayarlanmalıdır istiyorum (bu durumda 'myapp.foo'). Bu nasıl yapılabilir?

+0

.. bir başka giriş noktası komut bar.py çağırır varsayın ve böylece 'caller_name' olamaz' –

+1

emin senin örnek kod doğru olduğunu misiniz __main__'? Myapp/bar.py gövdesi olmamalıdır: import foo; foo.info ('Merhaba') # => [myapp.bar] Merhaba –

+0

Doğru, kodu çözdüm. –

cevap

91

ara üzerinden kontrol modülü:

inspect.stack() yığın bilgilerini döndürür. Bir Fonksiyonun içerisinde

, inspect.stack()[1] senin arayanın yığını dönecektir. Oradan, detaylar için dokümanlar bakın vb

arayanın işlev adı, modül, hakkında daha fazla bilgi alabilirsiniz: Ayrıca

http://docs.python.org/library/inspect.html

Doug Hellmann incelemek modülün güzel writeup sahip olduğu onun PyMOTW serisi:

http://pymotw.com/2/inspect/index.html#module-inspect

DÜZENLEME: İşte bazı kod istediğini yapar ki, sanırım:

def info(msg): 
    frm = inspect.stack()[1] 
    mod = inspect.getmodule(frm[0]) 
    print '[%s] %s' % (mod.__name__, msg) 
+1

Peki, 'inspect' modülünü kullanarak bu modülün '__name__' özniteliğini nasıl elde edersiniz? Örneğin yukarıdaki örneğimde myapp.foo'yu ('myapp/foo.py' değil) nasıl geri alabilirim? SO'da yayınlamadan önce inceleme modülünü kullanmayı denedim. –

+0

Sadece cevabı güncelledim. Bu senin ucunda mı çalışıyor? – ars

+6

Bunun, ithalat kancalarıyla garip bir şekilde etkileşime gireceğini, ironpython üzerinde çalışmayacağını ve jython üzerinde şaşırtıcı şekillerde hareket edebileceğini unutmayın.Bunun gibi büyüyü engellerseniz en iyisi olur. – Glyph

2

Bunu önermiyoruz, ancak aşağıdaki yöntemi ile hedefinizi gerçekleştirmek için şu şekildedir:

def caller_name(): 
    frame=inspect.currentframe() 
    frame=frame.f_back.f_back 
    code=frame.f_code 
    return code.co_filename 

Ardından mevcut yöntemi güncelleme:

def info(msg): 
    caller = caller_name() 
    print '[%s] %s' % (caller, msg) 
+6

Dosya adı '__name__' –

16

benzer karşı karşıya kalan sorun, ben sys modülünden sys._current_frames() en azından belirli kullanım örnekleri içinde, teftiş ithal etmek gerek kalmadan, size yardımcı olabilir ilginç bilgiler içerdiğini tespit etmiştir.

>>> sys._current_frames() 
{4052: <frame object at 0x03200C98>} 

Ardından f_back kullanarak "yukarı taşımak" olabilir:

>>> f = sys._current_frames().values()[0] 

>>> print f.f_back.f_globals['__file__'] 
'/base/data/home/apps/apricot/1.6456165165151/caller.py' 

>>> print f.f_back.f_globals['__name__'] 
'__main__' 

ayrıca f.f_back.f_code.co_filename kullanabilirsiniz dosya, yukarıda Mark Roddy tarafından önerildiği gibi. Bu yöntemin sınırlarından ve uyarılarından emin değilim (birden çok konu büyük olasılıkla bir problem olacaktır) ama bunu benim durumumda kullanmak niyetindeyim.

+1

ile aynı değildir. Not: pdf ile exe derledikten sonra inspect.stack kodu FAILS, ancak sys._current_frames WORKS FINE kullanarak derlendiğinden ... bu benim için tercih edilen tekniktir. – panofish

+5

Sanırım sys'i çağırmak yerine, önceki kareyi ['sys._getframe (1)'] (https://docs.python.org/3/library/sys.html#sys._getframe) ile almak daha kolay. _current_frames() '(btw her iş parçacığı için bir çerçeve eşleme döndüren). – hooblei

+0

sen hooblei ederiz, henüz test ama çok kanallı durumlar için çok kullanışlı görünüyor değil. –

İlgili konular