Python'da işlev modülünü çağırmak için __name__ alın


99

Varsayalım myapp/foo.py:

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

Ve myapp/bar.pyşunları içerir:

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

Bu durumda çağıran işlevler modülünün ('myapp.foo' olan) özniteliğine caller_nameayarlanmasını istiyorum __name__. Bu nasıl yapılabilir?


Başka bir giriş noktası komut dosyasının bar.py .. 'yi çağırdığını ve bu nedenle caller_nameolamayacağını varsayalım__main__
Sridhar Ratnakumar

Yanıtlar:


126

İnceleme modülüne göz atın:

inspect.stack() yığın bilgilerini döndürür.

Bir işlevin içinde, inspect.stack()[1]arayanın yığınını döndürür. Oradan, arayanın işlev adı, modülü vb. Hakkında daha fazla bilgi alabilirsiniz.

Ayrıntılar için belgelere bakın:

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

Ayrıca Doug Hellmann, PyMOTW serisindeki inceleme modülünün güzel bir yazısına sahip:

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

DÜZENLEME: İşte istediğinizi yapan bazı kodlar, bence:

import inspect 

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

1
Peki, __name__modülü kullanarak bu modülün niteliğini nasıl elde edersiniz inspect? Örneğin, yukarıdaki örneğimde nasıl geri döneceğim myapp.foo( geri dönmeyeceğim myapp/foo.py)? SO'ya göndermeden önce inspect modülünü kullanmayı denedim.
Sridhar Ratnakumar

6
Bunun içe aktarma kancalarıyla garip bir şekilde etkileşime gireceğini, ironpython'da çalışmayacağını ve jython'da şaşırtıcı şekillerde davranabileceğini unutmayın. Böyle bir sihirden kaçınmanız en iyisidir.
Glyph

2
Ayrıca, bir yığın çerçevesine referans tutmanın Python'un GC'sinin düzgün çalışmasını engelleyebileceğini unutmayın. Burada uyarıya bakın: docs.python.org/library/inspect.html#the-interpreter-stack
Kamil Kisiel

6
Arayan işlevi dekore edilmişse (@ ...), inspect.stack()[2]gerçek arayan için erişmeniz gerektiğini unutmayın .
Amir Ali Akbari

Ayrıca, pyinstaller kullanarak python kodunuzu bir exe'ye derlediğinizde bu mantığın düzgün çalışmadığını unutmayın.
panofish

19

Benzer bir sorunla karşılaştığımda, sys modülündeki sys._current_frames () işlevinin , en azından belirli kullanım durumlarında , inspect'i içe aktarmaya gerek kalmadan size yardımcı olabilecek ilginç bilgiler içerdiğini buldum .

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

Daha sonra f_back kullanarak "yukarı" hareket edebilirsiniz:

>>> f = sys._current_frames().values()[0]
>>> # for python3: f = list(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__'

Dosya adı için, yukarıda Mark Roddy tarafından önerildiği gibi, f.f_back.f_code.co_filename de kullanabilirsiniz. Bu yöntemin sınırlarından ve uyarılarından emin değilim (birden fazla iş parçacığı büyük olasılıkla bir sorun olacaktır) ama benim durumumda kullanmayı düşünüyorum.


2
not: inspect.stack kodu, pyinstaller kullanarak exe'ye derlendikten sonra FAILS, ancak sys._current_frames kullanılarak ÇALIŞIYOR ... yani bu benim için tercih edilen tekniktir.
panofish

7
Önceki çerçeveyi sys._getframe(1)çağırmak yerine sys._current_frames()(her iş parçacığı için bir çerçeve eşlemesi döndüren btw) elde etmenin daha kolay olduğunu düşünüyorum .
hooblei

Teşekkürler hooblei, henüz test etmedim ama çok iş parçacıklı durumlar için çok faydalı görünüyor.
Louis LC

Onun inspect.currentframe()yerine kullanmayı tercih ederim sys._current_frames().values()[0].
Aran-Fey

3

Bunu yapmanızı tavsiye etmiyorum, ancak aşağıdaki yöntemle hedefinize ulaşabilirsiniz:

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

Ardından mevcut yönteminizi aşağıdaki gibi güncelleyin:

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

7
Dosya adı ile aynı değil__name__
Sridhar Ratnakumar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.