Bir modülün yolu nasıl alınır?


755

Modülün değişip değişmediğini tespit etmek istiyorum. Şimdi, inotify'ı kullanmak basittir, sadece bildirim almak istediğiniz dizini bilmeniz gerekir.

Python'da bir modülün yolunu nasıl alabilirim?


1
Modülefinder'a göz atın: docs.python.org/library/modulefinder.html

9
Hala bu sitede arıyorsanız, doğru yanıt güncelleyin bu . Önerilen çözümden çok daha temizdir ve __file__ayarlanmadığı durumlarda da çalışır .
erikbwork

3
@ erikb85: sadece daha temiz değil; inspecttabanlı çözüm ayrıca çalışır execfile()durumda __file__sessizce yanlış isim üretir.
jfs


import pathlib, module; pathlib.Path(module.__file__).resolve().parentPlatformdan
bağımsız

Yanıtlar:


906
import a_module
print(a_module.__file__)

Aslında, en azından Mac OS X'de yüklenen .pyc dosyasının yolunu verecektir. Yani sanırım yapabilirsiniz:

import os
path = os.path.abspath(a_module.__file__)

Ayrıca deneyebilirsiniz:

path = os.path.dirname(a_module.__file__)

Modül dizinini almak için.


54
bu, içe aktardığınız modülün yolunu nasıl alacağınıza cevap verir, ancak içinde bulunduğunuz modülün / komut dosyasının değil (çalıştırdığınız komut dosyası __file__için tam bir yol değildir, görecelidir). İçinde bulunduğum dosya için aynı dizinden başka bir modül almak ve burada gösterildiği gibi yapmak zorunda kaldım. Daha uygun bir yol bilen var mı?
Ben Bryant

5
@hbdgaf, yerleşik olarak böyle bir şey olmadığından eminself.__file__
Dan Passaro

26
@BenBryant @hbdgaf os.path.dirname(__file__)benim için iyi çalışıyor ve modül dizininin abs yolunu döndürüyor.
Niccolò

9
Bunu yapmayı denedim ve izlemeyi aldım: AttributeError: 'module' object has no attribute '__file__'
Dorian Dore

5
Modüller ile biraz uğraşıyordum ve bir çözüm buldum path = module.__path__.__dict__["_path"][0], ancak taşınabilir olup olmadığından veya python sürümleri arasında farklı olmadığından emin değilim. Bana aynı hatayı veren ve inspectcevabını veren bu cevabın aksine benim için çalışıyor TypeError: <module 'module' (namespace)> is a built-in module...
Jezor

279

inspectPython'da modül var .

Resmi belgeler

Denetleme modülü, modüller, sınıflar, yöntemler, işlevler, geri izleme, çerçeve nesneleri ve kod nesneleri gibi canlı nesneler hakkında bilgi almanıza yardımcı olacak birkaç kullanışlı işlev sunar. Örneğin, bir sınıfın içeriğini incelemenize, bir yöntemin kaynak kodunu almanıza, bir işlev için bağımsız değişken listesini çıkarmanıza ve biçimlendirmenize ya da ayrıntılı bir geri izleme görüntülemek için gereken tüm bilgileri almanıza yardımcı olabilir.

Misal:

>>> import os
>>> import inspect
>>> inspect.getfile(os)
'/usr/lib64/python2.7/os.pyc'
>>> inspect.getfile(inspect)
'/usr/lib64/python2.7/inspect.pyc'
>>> os.path.dirname(inspect.getfile(inspect))
'/usr/lib64/python2.7'

7
inspectGeçerli dosyanın adını almak için de kullanabilirsiniz ; bkz. stackoverflow.com/a/50905/320036
z0r

5
Bu soruyu birçok kez araştırdım ve bu şimdiye kadar gördüğüm en makul cevap! Lütfen hakkında bilgi güncelleyininspect.currentframe()
erikbwork

inspect.getfile()yaklaşım modülü ile çalışmaz _io, ancak modül ile çalışır io.
smwikipedia

70

Diğer cevapların söylediği gibi, bunu yapmanın en iyi yolu __file__(aşağıda tekrar gösterilmiştir). Bununla birlikte, __file__modülü kendi başına çalıştırıyorsanız (yani gibi __main__) mevcut olmayan önemli bir uyarı vardır .

Örneğin, iki dosyanız olduğunu varsayalım (her ikisi de PYTHONPATH'ınızdadır):

#/path1/foo.py
import bar
print(bar.__file__)

ve

#/path2/bar.py
import os
print(os.getcwd())
print(__file__)

Foo.py çalıştırıldığında çıktı verilir:

/path1        # "import bar" causes the line "print(os.getcwd())" to run
/path2/bar.py # then "print(__file__)" runs
/path2/bar.py # then the import statement finishes and "print(bar.__file__)" runs

Ancak bar.py dosyasını kendi başına çalıştırmayı denerseniz, şunları elde edersiniz:

/path2                              # "print(os.getcwd())" still works fine
Traceback (most recent call last):  # but __file__ doesn't exist if bar.py is running as main
  File "/path2/bar.py", line 3, in <module>
    print(__file__)
NameError: name '__file__' is not defined 

Bu yardımcı olur umarım. Bu uyarı sunulan diğer çözümleri test ederken bana çok zaman ve karışıklık getirdi.


5
Bu durumda, dosya yerine sys.argv [0] kullanabilirsiniz .
Jimothy

4
Bu sürüme özgü bir uyarı mı? 2,6 ve 2,7, ben başarıyla güvenmek dosyası dosyasını çalıştığı, ne zaman adı __ == '__ ana '. Gördüğüm tek başarısızlık durumu "python -c 'print file '". Bazen emacs gibi IDE'ler geçerli arabelleği yürüttüğünde gerçekleşen '<stdin>' dosyası olabileceğini de ekleyeceğim .
Paul Du Bois

1
Öncü ve sondaki "__" karakterlerinin koyu harflerle yazıldığını unutmayın, bu yüzden önceki yorumları okurken bunu aklınızda bulundurun :-P
Paul Du Bois

1
@PaulDuBois Geri tiklerle çevreleyebilirsiniz: ` __file__` olur__file__
fncomp

1
Nasıl alırsın NameError? @ Paul Du Bois: Python 2,3-3,4 denedim ve __file__ancak Python dosyasını çalıştırın tanımlanır: python a.py, python -ma, ./a.py.
jfs

43

Bu soru üzerinde de birkaç varyasyonla uğraşmaya çalışacağım:

  1. çağrılan komut dosyasının yolunu bulma
  2. yürütülmekte olan komut dosyasının yolunu bulma
  3. çağrılan komut dosyasının dizinini bulma

(Bu soruların bazıları SO hakkında sorulmuştur, ancak kopya olarak kapatılmış ve buraya yeniden yönlendirilmiştir.)

Kullanım Uyarıları __file__

İçe aktardığınız bir modül için:

import something
something.__file__ 

modülün mutlak yolunu döndürür . Ancak, foo.py aşağıdaki komut dosyası göz önüne alındığında:

#foo.py
print '__file__', __file__

'Python foo.py' ile çağırmak sadece 'foo.py' döndürecektir. Bir shebang eklerseniz:

#!/usr/bin/python 
#foo.py
print '__file__', __file__

ve ./foo.py kullanarak çağırın, './foo.py' döndürecektir. Farklı bir dizinden çağırma (örneğin, dizin çubuğuna foo.py dosyasını koyma), ardından

python bar/foo.py

veya bir shebang ekleyip dosyayı doğrudan yürütme:

bar/foo.py

'bar / foo.py' ( göreceli yol) döndürecektir .

Dizini bulma

Şimdi dizini almak için oradan gitmek os.path.dirname(__file__)de zor olabilir. En azından sistemimde, dosyayı aynı dizinden çağırırsanız boş bir dize döndürür. ex.

# foo.py
import os
print '__file__ is:', __file__
print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)

çıktı olacak:

__file__ is: foo.py
os.path.dirname(__file__) is: 

Geçerli için kullanmak istiyorsanız bu güvenilir görünmüyor böylece diğer bir deyişle, boş bir dize döndürür dosyaya (karşıt olarak dosyaya bir ithal modülün). Bunu aşmak için, onu abspath çağrısı ile silebilirsiniz:

# foo.py
import os
print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))

hangi gibi bir çıktı üretir:

os.path.abspath(__file__) is: /home/user/bar/foo.py
os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar

Abspath () öğesinin sembolik bağlantıları ÇÖZMEZ olduğunu unutmayın. Bunu yapmak istiyorsanız, bunun yerine realpath () öğesini kullanın. Örneğin, aşağıdaki içeriğe sahip file_import_testing.py'yi işaret eden bir symlink file_import_testing_link yapmak:

import os
print 'abspath(__file__)',os.path.abspath(__file__)
print 'realpath(__file__)',os.path.realpath(__file__)

yürütme, mutlak yolları aşağıdaki gibi bir şey yazdırır:

abspath(__file__) /home/user/file_test_link
realpath(__file__) /home/user/file_test.py

file_import_testing_link -> file_import_testing.py

Inspect'i kullanma

@SummerBreeze denetleme modülünü kullanarak bahseder .

Bu, içe aktarılan modüller için iyi çalışıyor ve oldukça özlü:

import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)

itaatkâr olarak mutlak yolu döndürür. Ancak şu anda yürütülen komut dosyasının yolunu bulmak için, bunu kullanmanın bir yolunu görmedim.


1
inspect.getfile (os) şu koddaki os .__ file__ ile aynıdır: def getfile (object): "" "Bir nesnenin hangi kaynak veya derlenmiş dosyada tanımlandığını bulun." "" if ismodule (object): if hasattr (object, ' file '): dönüş nesnesi .__ file__
idanzalz

4
inspect.getfile(inspect.currentframe())Çalışmakta olan komut dosyasının yolunu almak için kullanabilirsiniz .
jbochi

33

Neden kimse bu konuda konuşmuyor anlamıyorum, ama benim için en basit çözüm imp.find_module ("modulename") ( burada dokümantasyon ) kullanıyor:

import imp
imp.find_module("os")

Yolu ikinci pozisyonda olan bir demet verir:

(<open file '/usr/lib/python2.7/os.py', mode 'U' at 0x7f44528d7540>,
'/usr/lib/python2.7/os.py',
('.py', 'U', 1))

Bu yöntemin "incele" yöntemine göre avantajı, çalışmasını sağlamak için modülü içe aktarmanız gerekmemesidir ve girdi olarak bir dize kullanabilirsiniz. Örneğin, başka bir komut dosyasında çağrılan modülleri kontrol ederken kullanışlıdır.

DÜZENLE :

Python3'te importlibmodül şunları yapmalıdır:

Dokümanı importlib.util.find_spec:

Belirtilen modül için teknik özellikleri döndürün.

İlk olarak, sys.modules modülün önceden içe aktarılıp aktarılmadığını kontrol eder. Eğer öyleyse, sys.modules [name]. spec döndürülür. Bu Hiçbiri olarak ayarlanırsa, ValueError değeri yükseltilir. Modül sys.modules içinde değilse, sys.meta_path buluculara verilen 'path' değerine sahip uygun bir spesifikasyon aranır. Hiçbir özellik bulunamazsa hiçbiri döndürülmez.

Ad alt modül içinse (nokta içerir), üst modül otomatik olarak alınır.

Ad ve paket bağımsız değişkenleri importlib.import_module () ile aynı şekilde çalışır. Başka bir deyişle, göreli modül adları (baştaki noktalarla birlikte) işe yarar.


2
imp, python 2'de amortismana tabi DEĞİLDİR (mevcut sürüm 2.7.13). imp 3.4'ten beri python 3'te amortismana tabi tutulur. importlib bunun yerine python 3'te kullanılacaktır. Bu çözümü beğendim, çünkü gerçek içe aktarma başarısız olduğunda bile çalışıyor (örn. 32bit motor için 64bit modülü nedeniyle)
mdew

Ve gerçekten güzel 64 bit sqlite3 yolunu bulmaya çalışırken ve alma başarısız. Mükemmel.
rahvin_t

2
importlib.machinery.PathFinder().find_module("os").get_filename()imp.find_modulePython3 + 'da bulduğuma en kısa alternatif . Herkes kullanımını arıyorsa importlib.util.find_spec.
1919'da

Bu yöntem, modülün hangi sürümünün paylaşılan bir bilgisayardan içe aktarıldığını anlamak için kullandığım kadar büyük olan gerçek modülü içe aktarmadan çalışır.
Gouda

19

Bu önemsizdi.

Her modülün şu __file__anda bulunduğunuz yerden göreceli yolunu gösteren bir değişkeni vardır.

Bu nedenle, modülün bildirilmesi için bir dizin almak şu şekilde basittir:

os.path.dirname(__file__)

14
Neredeyse ama çok doğru - dosyası olduğunu değil "Şu an olduğun yerde göreli"; göreli olduğunda (yalnızca sys.path dosyasında göreli yollar olduğunda olur), modül yüklendiğinde bulunduğunuz yere görecelidir .
Charles Duffy

17
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)

1
__file__sadece dir / test.py olduğu için Linux python 2.6'mda çalışmıyor, abspath, istenen sonucu olmayan yol adını tamamlamak için cwd'yi içeriyor, ancak bir modülü içe aktarırsanız m.__file__istenen sonucu verir.
Ben Bryant

10
import module
print module.__path__

Paketler bir özel özelliği daha destekler __path__. Bu, __init__.pyo dosyadaki kod yürütülmeden önce paketin bulunduğu dizinin adını içeren bir liste olarak başlatılır . Bu değişken değiştirilebilir; bu, pakette bulunan modül ve alt paketlerin gelecekteki aramalarını etkiler.

Bu özelliğe sıklıkla ihtiyaç duyulmamakla birlikte, bir pakette bulunan modül grubunu genişletmek için kullanılabilir.

Kaynak


9

Komut Satırı Yardımcı Programı

Bir komut satırı yardımcı programına ince ayar yapabilirsiniz,

python-which <package name>

resim açıklamasını buraya girin


Oluşturmak /usr/local/bin/python-which

#!/usr/bin/env python

import importlib
import os
import sys

args = sys.argv[1:]
if len(args) > 0:
    module = importlib.import_module(args[0])
    print os.path.dirname(module.__file__)

Yürütülebilir yap

sudo chmod +x /usr/local/bin/python-which

7

Bu yüzden py2exe ile bunu yapmaya çalışırken adil bir süre geçirdim Sorun bir python komut dosyası veya bir py2exe yürütülebilir olarak çalıştırılıyor komut dosyasının temel klasörünü almak oldu. Ayrıca, geçerli klasörden, başka bir klasörden veya (en zor olanıysa) sistemin yolundan çalıştırılıp çalıştırılmadığının çalışmasını sağlamak.

Sonunda sys.frozen py2exe çalışan bir gösterge olarak kullanarak, bu yaklaşımı kullandım:

import os,sys
if hasattr(sys,'frozen'): # only when running in py2exe this exists
    base = sys.prefix
else: # otherwise this is a regular python script
    base = os.path.dirname(os.path.realpath(__file__))

7

sadece modülünüzü içe aktarabilir ve ismine varabilirsiniz.

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>

4

Paketin kök yolunu modüllerinden herhangi birinden almak istiyorsanız, aşağıdakiler çalışır (Python 3.6'da test edilmiştir):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

Bunun yerine ana __init__.pyyola da başvurulabilir __file__.

Bu yardımcı olur umarım!


3

Kullanmanın tek uyarısı __file__geçerli olduğunda, göreli dizin boşsa (yani, komut dosyasının bulunduğu aynı dizinden bir komut dosyası olarak çalıştırıldığında), önemsiz bir çözümdür:

import os.path
mydir = os.path.dirname(__file__) or '.'
full  = os.path.abspath(mydir)
print __file__, mydir, full

Ve sonuç:

$ python teste.py 
teste.py . /home/user/work/teste

Hile çağrıdan or '.'sonra dirname(). Sanki dir ayarlar .demektir geçerli dizin ve herhangi bir yol-ilgili fonksiyon için geçerli bir dizindir.

Bu nedenle, kullanmak abspath()gerçekten gerekli değildir. Ancak yine de kullanırsanız, hile gerekli değildir: abspath()boş yolları kabul eder ve geçerli dizin olarak uygun şekilde yorumlar.


Siparişi daha iyi değiştirin ve kullanın, os.path.dirname(os.path.abspath(__file__))çünkü o zaman göreli yollar hakkında endişelenmenize gerek yoktur. Hatalar için daha az fırsat.
szali

3

Tek bir ortak senaryoya (Python 3'te) katkıda bulunmak ve ona birkaç yaklaşımı keşfetmek istiyorum.

Yerleşik open () işlevi, göreceli veya mutlak yolu ilk bağımsız değişkeni olarak kabul eder. Göreli yol geçerli çalışma dizinine göreli olarak ele alınır, bu nedenle mutlak yolu dosyaya iletmeniz önerilir.

Basitçe söylemek gerekirse, aşağıdaki kodla bir komut dosyası çalıştırırsanız , dosyanın komut dosyasının bulunduğu dizinde oluşturulacağı garanti edilmezexample.txt :

with open('example.txt', 'w'):
    pass

Bu kodu düzeltmek için komut dosyasının yolunu almalı ve mutlak yapmalıyız. Yolun mutlak olmasını sağlamak için os.path.realpath () işlevini kullanıyoruz. Komut dosyasının yolunu almak için çeşitli yol sonuçlarını döndüren birkaç ortak işlev vardır:

  • os.getcwd()
  • os.path.realpath('example.txt')
  • sys.argv[0]
  • __file__

Her iki işlev de os.getcwd () ve os.path.realpath () , geçerli çalışma dizinine göre yol sonuçlarını döndürür . Genellikle istediğimiz gibi değil. Sys.argv listesinin ilk öğesi , listeyi kök komut dosyasının kendisinde veya modüllerinden herhangi birinde çağırmanıza bakılmaksızın kök komut dosyasının (çalıştırdığınız komut dosyası) yoludur . Bazı durumlarda kullanışlı olabilir. __FILE__ değişken denir olduğunda görülür modülün yolunu içerir.


Aşağıdaki kod example.txt, komut dosyasının bulunduğu dizinde doğru bir dosya oluşturur :

filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')

with open(filepath, 'w'):
    pass

3

Komut dosyanızdaki mutlak yolu bilmek istiyorsanız, Path nesnesini kullanabilirsiniz :

from pathlib import Path

print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())

cwd () yöntemi

Geçerli dizini temsil eden yeni bir yol nesnesi döndürme (os.getcwd () tarafından döndürüldüğü gibi)

solve () yöntemi

Simgeleri çözerek yolu mutlak yapın. Yeni bir yol nesnesi döndürülür:


1

Bir python paketinin modüllerinden paketle aynı dizinde bulunan bir dosyaya başvurmak zorunda kaldım. Ör.

some_dir/
  maincli.py
  top_package/
    __init__.py
    level_one_a/
      __init__.py
      my_lib_a.py
      level_two/
        __init__.py
        hello_world.py
    level_one_b/
      __init__.py
      my_lib_b.py

Bu yüzden yukarıda top_package ve maincli.py'nin aynı dizinde olduğunu bilerek my_lib_a.py modülünden maincli.py'yi çağırmak zorunda kaldım. İşte maincli.py yolunu almak için:

import sys
import os
import imp


class ConfigurationException(Exception):
    pass


# inside of my_lib_a.py
def get_maincli_path():
    maincli_path = os.path.abspath(imp.find_module('maincli')[1])
    # top_package = __package__.split('.')[0]
    # mod = sys.modules.get(top_package)
    # modfile = mod.__file__
    # pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile)))
    # maincli_path = os.path.join(pkg_in_dir, 'maincli.py')

    if not os.path.exists(maincli_path):
        err_msg = 'This script expects that "maincli.py" be installed to the '\
        'same directory: "{0}"'.format(maincli_path)
        raise ConfigurationException(err_msg)

    return maincli_path

PlasmaBinturong tarafından gönderilen göre kodu değiştirdim.


1

Bunu bir "program" içinde dinamik olarak yapmak istiyorsanız şu kodu deneyin:
Demek istediğim, "sabit kod " modülün tam adını bilmiyor olabilirsiniz. Bir listeden seçilebilir veya __file__ kullanmak için şu anda çalışmıyor olabilir.

(Biliyorum, Python 3'te çalışmayacak)

global modpath
modname = 'os' #This can be any module name on the fly
#Create a file called "modname.py"
f=open("modname.py","w")
f.write("import "+modname+"\n")
f.write("modpath = "+modname+"\n")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:\Python27\lib\os.pyc'>

"Küresel" sorundan kurtulmaya çalıştım ama işe yaramadığı durumlarda Python 3'te "execfile ()" benzetilebileceğini düşünüyorum. Bu bir programda olduğu için, kolayca yeniden kullanın.


0

Pip kullanarak yüklediyseniz, "pip show" harika çalışır ('Konum')

$ pip show detektör2

Name: detectron2
Version: 0.1
Summary: Detectron2 is FAIR next-generation research platform for object detection and segmentation.
Home-page: https://github.com/facebookresearch/detectron2
Author: FAIR
Author-email: None
License: UNKNOWN
Location: /home/ubuntu/anaconda3/envs/pytorch_p36/lib/python3.6/site-packages
Requires: yacs, tabulate, tqdm, pydot, tensorboard, Pillow, termcolor, future, cloudpickle, matplotlib, fvcore

0

İşte herkes için yararlı olması durumunda hızlı bir bash betiği. Ben sadece pushdkod için bir ortam değişkeni ayarlamak mümkün olmak istiyorum .

#!/bin/bash
module=${1:?"I need a module name"}

python << EOI
import $module
import os
print os.path.dirname($module.__file__)
EOI

Kabuk örneği:

[root@sri-4625-0004 ~]# export LXML=$(get_python_path.sh lxml)
[root@sri-4625-0004 ~]# echo $LXML
/usr/lib64/python2.7/site-packages/lxml
[root@sri-4625-0004 ~]#
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.