2009-03-02 13 views
22

Geçerli yürütme modülünü veya sınıf adını, içe aktarılan bir modül içinden dinamik olarak alabilmek istiyorum. İşte bazı kod:Geçerli yürütme modülüne veya sınıf adına Python'da nasıl erişebilirim?

foo.py:

def f(): 
    print __name__ 

bar.py:

from foo import f 

def b(): f() 

Bu açıkça __name__ gibi çalışmıyor içeren modülün adıdır işlev. foo modülüne erişmek istediğim, foo kullanan geçerli yürütme modülünün adıdır. Yukarıdaki durumda, bar olur, ancak başka bir modül foo ithal edildiyse, foo'un, bu modülün adında dinamik olarak erişmesini istiyorum.

Düzenleme:inspect modülü oldukça umut verici görünüyor ama tam olarak aradığım şey değil. Beklediğim şey, mevcut yürütme modülünün adını içerecek erişebildiğim bir tür küresel veya ortam düzeyi değişkendi. Bu bilgiyi bulmak için yığının üstesinden gelmek istemediğimden değil - Python'un bu verileri zaten açığa çıkarmış olabileceğini düşündüm.

Düzenleme: Bunu nasıl kullanmaya çalıştığım İşte. Her ikisi de hataların dosyaya kaydedilmesi gereken iki farklı Django uygulamasına sahibim. "AppOne" ve "AppTwo" olarak adlandırıldığını söylüyoruz. Ayrıca şu dosyaları kaydetmeyi istediğim bir yer var: "/home/hare/app_logs". Herhangi bir noktada her uygulamada, logger modülümü içe aktarabilmek ve log dizisini dosyaya yazan log fonksiyonunu çağırmak istiyorum. Ancak yapmak istediğim, her uygulamanın günlük dosyalarının ilgili günlük dizinlerinde yer alabilmesi için geçerli uygulamanın ("AppOne" veya "AppTwo") adı olan app_logs'un altında bir dizin oluşturmaktır.

Bunu yapmak için, kayıt defteri modülünün, ana günlük dizininin yerini bilmekten sorumlu olan ve geçerli uygulamanın adını belirten bir tür küresel değişkene erişebilmesi için en iyi yolun olacağını düşündüm ve Henüz mevcut değilse, uygulamanın günlüğe kaydetme dizinini oluşturma.

+0

Neden böyle sorumluluk tahsisini kırmak isteyeyim ? –

+1

Bunu bir günlüğe kaydetme modülü içinde kullanıyorum - Arayanın bir tür anahtarı geçmesi gerekmeden hangi dış modülün oturum açmaya çalıştığını söylemek istiyorum. –

+0

Program yürütme işlemini başlatan modülü bulmaya çalışıyorsunuz (yani: __name__ == '__main__' olan modül veya tam olarak foo.f() adı verilen modül, her defasında farklı olabilir foo.f() –

cevap

40

Yorumdan - soru değil.

Sadece ne yapmaya çalıştığımı görmek isteyip istemediğimi merak ediyorum.

"Mümkün" yanıtı her zaman "evet" dir. Her zaman. Sorunuz zaman yolculuğu, anti-yerçekimi veya sürekli hareket içermiyorsa.

Yanıt her zaman "evet" olduğundan, sorunuz yanlış biçimlendirilmiştir. Asıl soru, "günlüğe kaydetme modülümün müşterinin adını bilmesi için iyi bir yol nedir?" ya da böyle bir şey.

Yanıt "Bir parametre olarak kabul et." Gizemli globals veya diğer hileleri incelemek veya aramakla uğraşmayın.

Sadece logging.getLogger (tasarım deseni takip) ve açıkça adlandırılmış kaydedici kullanın. Ortak bir deyim, hemen hemen tüm günlük adlandırmalarını mükemmel şekilde ele alır.

+1

Bence haklısın, yaklaşımımı ayarlamaktan daha iyi olacağım - teşekkürler! –

+0

CS profesörlerimden biri, endüstride çalışırken öğrendiğini ve birisinin "X yapabilir misin?" Onun cevabı "Yeterince zaman ve para verilen her şeyi yapabilirim." –

+5

İçe aktarma yerine komut dosyasını çalıştırırsam da, '__name__' komut dosyasının gerçek yolunu yerine '__main__' (' modA.submodB.pack1' gibi) içermelidir. * Her zaman * nasıl çağırıldığına bakılmaksızın modül yolunu döndüren bir değer var mı? – estani

3

Bu, foo kapsamının dışında olduğundan mümkün olduğuna inanmıyorum. foo sadece sayısız diğer modüller ve uygulamalar tarafından çağrılabileceğinden iç kapsamının farkında olacaktır.

11

Kullanmak istediğiniz şeyin python çalışma zamanı yığınını denetlemek için inspect modülü olduğunu düşünüyorum. Bu tutorial göz atın. Yapmak istediğiniz şeyin neredeyse tam bir örneğini sağladığını düşünüyorum.

+0

+ 1'e bakın, bu iyi bir bulgudur. –

+7

Bağlantı bozuk. –

15

"Yürütülmekte olan modül" ifadesi, şu anda çalıştırılan işlevi içerdiği gibi açık bir şekilde foo'dur - istediğinizi daha iyi tanımlayın. Foo'nun hemen arayanın modülüdür. fo (fo) işlevini çubuğun içinde bir işlevle çağırır. Ne kadar ileride gitmek istediğinize bağlıdır.

Her durumda, hemen arayanı kabul ederseniz, bunu elde edebilirsiniz. Çağrı yığınının yukarı doğru ilerlemesiyle, sys._getframe numaralı telefonu arayarak, uygun seviyelerde yürüyebilirsiniz.

def f(): 
    caller = sys._getframe(1) # Obtain calling frame 
    print "Called from module", caller.f_globals['__name__'] 

[Düzenleme]: Aslında, yukarıda açıklandığı gibi inspect modülünü kullanarak yığın çerçevesi elde etmek için bir temiz bir şekilde muhtemelen. eşdeğer kodudur:

def f(): 
    caller = inspect.currentframe().f_back 
    print "Called from module", caller.f_globals['__name__'] 

(sys._getframe dahili kullanım için olan olarak belgelenmiştir - modül daha güvenilir bir API olduğunu incelemek) Ben piton yaptık beri

1

Bir süre oldu, ama ben traceback aracılığıyla bir arayanın globals ve yerlileri erişebilirsiniz inanıyorum.

7

__file__ çağrı yapıldığında geçerli modülün yoludur.

24

Bu akım modülü referans gösterdiği için çalışması gerekir:

import sys 
sys.modules[__name__] 
1

başka "__main__" modülünde bir başvuru almak için:

import sys 
sys.modules['__main__'] 

sonra modülün dosya yolunu elde etmek için, hangi içeren Adından:

sys.modules['__main__'].__file__ 

"__main__" modülü içinde, sadece kullanıyorsanız: __file__

dosya yolu sadece dosya adını elde etmek için:

file_name.split(".")[0] 

sınıf örneğinin adını edinmek için:

import os 
os.path.basename(file_path) 

onun uzantısı dosya adını ayırmak için

Bir sınıfın adını edinmek için:
class.__name__ 
2

Yalnızca, __file__'u kullanmak, ana modül için göreli bir yol ve içe aktarılan modüller için mutlak yol sağlar. Bunun farkında olmamızla, os.path araçlarımızın küçük bir yardımı ile modül dosyasını sürekli olarak alabiliyoruz.

Dosya adı için yalnızca __file__.split(os.path.sep)[-1] kullanın.

Yolun tamamı için os.path.abspath(__file__) kullanın.

Demo:

/tmp $ cat f.py 
from pprint import pprint 
import os 
import sys 

pprint({ 
    'sys.modules[__name__]': sys.modules[__name__], 
    '__file__': __file__, 
    '__file__.split(os.path.sep)[-1]': __file__.split(os.path.sep)[-1], 
    'os.path.abspath(__file__)': os.path.abspath(__file__), 
}) 

/tmp $ cat i.py 
import f 

Sonuçlar:

## on *Nix ## 

/tmp $ python3 f.py 
{'sys.modules[__name__]': <module '__main__' from 'f.py'>, 
'__file__': 'f.py', 
'__file__.split(os.path.sep)[-1]': 'f.py', 
'os.path.abspath(__file__)': '/tmp/f.py'} 

/tmp $ python3 i.py 
{'sys.modules[__name__]': <module 'f' from '/tmp/f.pyc'>, 
'__file__': '/tmp/f.pyc', 
'__file__.split(os.path.sep)[-1]': 'f.pyc', 
'os.path.abspath(__file__)': '/tmp/f.pyc'} 

## on Windows ## 

PS C:\tmp> python3.exe f.py 
{'sys.modules[__name__]': <module '__main__' from 'f.py'>, 
'__file__': 'f.py', 
'__file__.split(os.path.sep)[-1]': 'f.py', 
'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'} 

PS C:\tmp> python3.exe i.py 
{'sys.modules[__name__]': <module 'f' from 'C:\\tools\\cygwin\\tmp\\f.py'>, 
'__file__': 'C:\\tools\\cygwin\\tmp\\f.py', 
'__file__.split(os.path.sep)[-1]': 'f.py', 
'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'} 

sonuna kapalı '.py' şerit istiyorsanız, kolayca yapabilirsiniz. (Ama bunun yerine '.pyc' çalıştırabilir unutmayın.)

+0

herhangi bir nedenle '__spile __. Split (os.path.sep) [- 1]' yerine 'os.path.basename (__file __) '? – cowbert

1

dosyanın sadece ismini isterseniz:

file_name = __file__.split("/")[len(__file__.split("/"))-1] 
İlgili konular