Python modülünün içe aktarılmadan var olup olmadığı nasıl kontrol edilir


179

İçe aktarmadan bir python modülünün olup olmadığını bilmem gerekir.

Varolmayan bir şeyi içe aktarma (istediğim değil):

try:
    import eggs
except ImportError:
    pass

4
Merak ediyorum, ithalat kullanmanın dezavantajları nelerdir?
Chuck

15
Modülünüzün yan etkileri varsa, içe aktarma işlemini çağırmanın istenmeyen sonuçları olabilir. Bu nedenle, önce bir dosyanın hangi sürümünün çalıştırılacağını kontrol etmek isterseniz, aşağıdaki cevabı kontrol edebilir ve içe aktarmayı daha sonra yapabilirsiniz. Yan etkileri olan modüller yazmanın iyi bir fikir olduğunu düşünmüyorum - ama hepimiz yetişkiniz ve ne kadar tehlikeli kodlamak istediğimiz konusunda kendi kararlarımızı verebiliriz.
yarbelk


1
@ArtOfWarfare Sadece kapalı olduğu soru tekrarı olarak bağlantılı bu one. Çünkü bu soru daha açık ve burada önerilen çözüm burada listelenen diğer tüm çözümlerden daha iyi. Bu çözümü daha iyi kimin istediğini, insanları ondan uzaklaştırmak yerine işaret etmeyi tercih ederim.
Bakuriu

7
@Chuck Ayrıca modül var olabilir, ancak içe aktarma hataları içerebilir. Yukarıdaki kodda olduğu gibi ImportErrors öğesinin yakalanması, modülün var olmadığında, gerçekte hatalara sahip olduğunda gösterilmesine yol açabilir.
Michael Barton

Yanıtlar:


199

Python2

İçe aktarmanın python2'de bir şey bulup bulamayacağını kontrol etmek için imp

import imp
try:
    imp.find_module('eggs')
    found = True
except ImportError:
    found = False

Noktalı ithalatları bulmak için daha fazlasını yapmanız gerekir:

import imp
try:
    spam_info = imp.find_module('spam')
    spam = imp.load_module('spam', *spam_info)
    imp.find_module('eggs', spam.__path__) # __path__ is already a list
    found = True
except ImportError:
    found = False

Ayrıca kullanabilirsiniz pkgutil.find_loader(az çok python3 kısmı ile aynı

import pkgutil
eggs_loader = pkgutil.find_loader('eggs')
found = eggs_loader is not None

Python3

Python3 ≤ 3.3

Kullanmalısınız importlib, Bunu nasıl yaptım?

import importlib
spam_loader = importlib.find_loader('spam')
found = spam_loader is not None

Benim beklentim, bunun için bir yükleyici bulabilirseniz, o zaman var. Hangi yükleyicileri kabul edeceğinizi filtrelemek gibi, bu konuda biraz daha akıllı olabilirsiniz. Örneğin:

import importlib
spam_loader = importlib.find_loader('spam')
# only accept it as valid if there is a source file for the module - no bytecode only.
found = issubclass(type(spam_loader), importlib.machinery.SourceFileLoader)

Python3 ≥ 3.4

Python3.4'te importlib.find_loader python belgeleri lehine itiraz edilmiştir importlib.util.find_spec. Önerilen yöntem importlib.util.find_spec. importlib.machinery.FileFinderYüklemek için belirli bir dosyanın peşindeyseniz faydalı olan başkaları da vardır . Bunların nasıl kullanılacağını bulmak bunun kapsamı dışındadır.

import importlib
spam_spec = importlib.util.find_spec("spam")
found = spam_spec is not None

Bu, göreli ithalatlarla da çalışır, ancak başlangıç ​​paketini sağlamanız gerekir, böylece şunları da yapabilirsiniz:

import importlib
spam_spec = importlib.util.find_spec("..spam", package="eggs.bar")
found = spam_spec is not None
spam_spec.name == "eggs.spam"

Eminim bunu yapmak için bir neden var - ne olacağından emin değilim.

UYARI

Bir alt modül bulmaya çalışırken, ana modülü içe aktarır ( yukarıdaki yöntemlerin tümü için )!

food/
  |- __init__.py
  |- eggs.py

## __init__.py
print("module food loaded")

## eggs.py
print("module eggs")

were you then to run
>>> import importlib
>>> spam_spec = importlib.find_spec("food.eggs")
module food loaded
ModuleSpec(name='food.eggs', loader=<_frozen_importlib.SourceFileLoader object at 0x10221df28>, origin='/home/user/food/eggs.py')

Bu konuda dolaşmaya yorumlarınızı bekliyoruz

Teşekkür

  • importlib için @rvighne
  • @ lucas-guido python3.3 + için find_loader
  • python'daki pkgutils.find_loader davranışı için @enpenax

3
Bu sadece üst seviye modüller için geçerlidir, değil eggs.ham.spam.
hemflit

3
@hemflit spamiçinde bulmak eggs.hamistiyorsanız kullanmak istiyorsunuzimp.find_module('spam', ['eggs', 'ham'])
gitaarik

5
1, fakat impedilir kaldırılmış lehine importlib3. Python
rvighne

4
İçe aktarılan modülde gerçek bir "ImportError" varsa. Bana olan buydu. Sonra modül var ama "bulunamaz".
enpenax

1
Bir yıl sonra yukarıda bahsettiğim aynı sorunla karşılaştım ve Python 2 için bir çözüm kazıyordum: pkgutil.find_loader("my.package.module")paket / modül varsa ve Nonedeğilse bir yükleyici döndürür . ImportError maskeleme dün beni çılgına çevirdi gibi Python 2 için cevabınızı güncelleyin
enpenax

13

Yarbelk'in yanıtını kullandıktan sonra, bunu ithal etmek zorunda kalmadım ìmp.

try:
    __import__('imp').find_module('eggs')
    # Make things with supposed existing module
except ImportError:
    pass

settings.pyÖrneğin Django'da kullanışlıdır .


4
Bu maskeyi modülde içe aktarma hataları içerdiğinden hatayı reddettim.
enpenax

1
Downvote kötü bir fikir, iyi bir uygulama "her zaman yakalanan hataları günlüğe kaydet". Bu, nasıl istediğinizi yazdıktan sonra bir örnektir.
Zulu

2
İçe aktarılan modül bir satırda ImportError ile başarısız olursa ve try catchiniz sessizce başarısız olursa nasıl bir hata kaydedersiniz?
enpenax

Ben sadece gerçek hayatta maskeleme-ithalat-hatalar sorunu ile karşılaştım, ve bu kötü oldu (geçmesi başarısız olmalıydı testleri neden!).
David

Birinin farklı bir modülde bir
maymun maymununu

13

Python 3> = 3.6: ModuleNotFoundError

ModuleNotFoundErrorGirmiştir piton 3.6 ve bu amaçla kullanılabilecek

try:
    import eggs
except ModuleNotFoundError:
    # Error handling
    pass

Bir modül veya ebeveynlerinden biri bulunamadığında hata oluşur . Yani

try:
    import eggs.sub
except ModuleNotFoundError as err:
    # Error handling
    print(err)

bakışlar ister belirten bir mesaj basacaktır No module named 'eggs'eğer eggsmodül bulunamıyor; ancak No module named 'eggs.sub'yalnızca submodül bulunamazsa,eggs paket .

Hakkında daha fazla bilgi için içe aktarma sisteminin belgelerine bakın .ModuleNotFoundError


1
Bu doe soruyu cevaplamıyor çünkü eğer varsa paketi ithal ediyor
divenex

11

ImportError'a güvenmeden Python 2

Mevcut cevap güncellenene kadar Python 2'nin yolu

import pkgutil
import importlib

if pkgutil.find_loader(mod) is not None:
    return importlib.import_module(mod)
return None

Neden başka bir cevap?

Bir çok cevap yakalamayı kullanır ImportError. Sorun şu ki, neyin attığını bilmiyoruzImportError .

Mevcut modülünüzü içe aktarırsanız ve ImportErrormodülünüzde bir (örneğin, 1. satırdaki yazım hatası) varsa, sonuç modülünüzün mevcut olmaması olacaktır. Modülünüzün var olduğunu ve ImportErroryakalandığını ve işlerin sessizce başarısız olduğunu anlamanız için geri izleme miktarını oldukça fazla alacaktır .


Belirsiz olabilir, ancak ilk kod blokları hariç tümü güvenilmez ImportError- lütfen sizin için belirsiz olup olmadığını düzenleyin.
yarbelk

İlk iki Python 2 örneğinde ImportError yakalamayı kullandığınızı görüyorum. Öyleyse neden oradalar?
enpenax

3
Mod == 'not_existing_package.mymodule' ise ImportError atar. Tam çözümümü aşağıda görebilirsiniz
Marcin Raczyński

1
Tabii ki bir ithalat hatası atıyor. Bir modül yoksa bir içe aktarma hatası atması gerekir. Bu şekilde gerekirse yakalayabilirsiniz. Diğer çözümlerle ilgili sorun, diğer hataları maskelemeleri.
enpenax

Denemek / hariç tutmak, giriş yapmamanız ya da bir şey sağlamamanız gerektiği anlamına gelmez. Altta yatan izlemeyi tamamen yakalayabilir ve istediğiniz her şeyi yapabilirsiniz.
Zulu

8

Bir astar olarak go_as'ın cevabı

 python -c "help('modules');" | grep module

6

Komut satırından bir modülün yüklenip yüklenmediğini kontrol etmenin bir yolunu ararken bu soruya rastladım ve benden sonra gelen ve aynı şeyi arayanlar için düşüncelerimi paylaşmak istiyorum:

Linux / UNIX kod dosyası yöntemi : bir dosya yapın module_help.py:

#!/usr/bin/env python

help('modules')

Ardından, yürütülebilir olduğundan emin olun: chmod u+x module_help.py

Ve ile aramanıza pipeiçin grep:

./module_help.py | grep module_name

Yerleşik yardım sistemini çağırın . (Bu işlev etkileşimli kullanım içindir .) Herhangi bir bağımsız değişken verilmezse, etkileşimli yardım sistemi yorumlayıcı konsolunda başlar. Bağımsız değişken bir dize ise , dize bir modül , işlev, sınıf, yöntem, anahtar sözcük veya belge konusunun adı olarak aranır ve konsolda bir yardım sayfası yazdırılır. Bağımsız değişken başka türde bir nesne ise, nesne üzerinde bir yardım sayfası oluşturulur.

Etkileşimli yöntem : konsol yükündepython

>>> help('module_name')

Yazarak okumadan q
çıkılırsa Python etkileşimli oturumundan çıkmak için Ctrl+D

Windows komut dosyası yöntemi de Linux / UNIX uyumlu ve genel olarak daha iyi :

#!/usr/bin/env python

import sys

help(sys.argv[1])

Komuttan şöyle çağırmak:

python module_help.py site  

Çıktı:

Modül sitesinde yardım:

NAME site - Üçüncü taraf paketleri için modül arama yollarını sys.path dosyasına ekleyin.

FILE /usr/lib/python2.7/site.py

MODULE DOCS http://docs.python.org/library/site

DESCRIPTION
...
:

qetkileşimli moddan çıkmak için tuşuna basmanız gerekir.

Bilinmeyen modülü kullanarak:

python module_help.py lkajshdflkahsodf

Çıktı:

için hiçbir Python belgesi bulunamadı

ve çıkın.


5

Pkgutil işlevlerinden birini kullanın , örneğin:

from pkgutil import iter_modules

def module_exists(module_name):
    return module_name in (name for loader, name, ispkg in iter_modules())


4

Tüm modülleri içe aktarmaya çalışan ve hangilerinin başarısız olduğunu ve hangilerinin işe yaradığını söyleyen küçük bir komut dosyası yazabilirsiniz:

import pip


if __name__ == '__main__':
    for package in pip.get_installed_distributions():
        pack_string = str(package).split(" ")[0]
        try:
            if __import__(pack_string.lower()):
                print(pack_string + " loaded successfully")
        except Exception as e:
            print(pack_string + " failed with error code: {}".format(e))

Çıktı:

zope.interface loaded successfully
zope.deprecation loaded successfully
yarg loaded successfully
xlrd loaded successfully
WMI loaded successfully
Werkzeug loaded successfully
WebOb loaded successfully
virtualenv loaded successfully
...

Uyarı kelimesi, her şeyiPyYAML failed with error code: No module named pyyaml içe aktarmaya çalışacak, böylece gerçek içe aktarma adı sadece yaml olduğundan, şeyleri göreceksiniz . İthalatınızı bildiğiniz sürece, bu sizin için hile yapmalıdır.


3

Bu yardımcı işlevi yazdım:

def is_module_available(module_name):
    if sys.version_info < (3, 0):
        # python 2
        import importlib
        torch_loader = importlib.find_loader(module_name)
    elif sys.version_info <= (3, 3):
        # python 3.0 to 3.3
        import pkgutil
        torch_loader = pkgutil.find_loader(module_name)
    elif sys.version_info >= (3, 4):
        # python 3.4 and above
        import importlib
        torch_loader = importlib.util.find_spec(module_name)

    return torch_loader is not None

2

Ayrıca importlibdoğrudan kullanabilirsiniz

import importlib

try:
    importlib.import_module(module_name)
except ImportError:
    # Handle error

Bunun gerçekten içe aktarma sorunu var. Yan etkiler ve hepsi
yarbelk

2

"Noktalı modül" in ana paketini içe aktarmadan güvenilir olup olmadığını kontrol etmenin bir yolu yoktur. Bunu söyleyerek, "Python modülünün olup olmadığını kontrol etme" sorununa birçok çözüm vardır.

Çözümün altında, içe aktarılan modülün ImportError'ı olsa bile artırabileceği sorunu ele alın. Bu durumu modülün mevcut olmadığı durumdan ayırmak istiyoruz.

Python 2 :

import importlib
import pkgutil
import sys

def find_module(full_module_name):
    """
    Returns module object if module `full_module_name` can be imported. 

    Returns None if module does not exist. 

    Exception is raised if (existing) module raises exception during its import.
    """
    module = sys.modules.get(full_module_name)
    if module is None:
        module_path_tail = full_module_name.split('.')
        module_path_head = []
        loader = True
        while module_path_tail and loader:
            module_path_head.append(module_path_tail.pop(0))
            module_name = ".".join(module_path_head)
            loader = bool(pkgutil.find_loader(module_name))
            if not loader:
                # Double check if module realy does not exist
                # (case: full_module_name == 'paste.deploy')
                try:
                    importlib.import_module(module_name)
                except ImportError:
                    pass
                else:
                    loader = True
        if loader:
            module = importlib.import_module(full_module_name)
    return module

Python 3 :

import importlib

def find_module(full_module_name):
    """
    Returns module object if module `full_module_name` can be imported. 

    Returns None if module does not exist. 

    Exception is raised if (existing) module raises exception during its import.
    """
    try:
        return importlib.import_module(full_module_name)
    except ImportError as exc:
        if not (full_module_name + '.').startswith(exc.name + '.'):
            raise

1

django.utils.module_loading.module_has_submodule içinde


import sys
import os
import imp

def module_has_submodule(package, module_name):
    """
    check module in package
    django.utils.module_loading.module_has_submodule
    """
    name = ".".join([package.__name__, module_name])
    try:
        # None indicates a cached miss; see mark_miss() in Python/import.c.
        return sys.modules[name] is not None
    except KeyError:
        pass
    try:
        package_path = package.__path__   # No __path__, then not a package.
    except AttributeError:
        # Since the remainder of this function assumes that we're dealing with
        # a package (module with a __path__), so if it's not, then bail here.
        return False
    for finder in sys.meta_path:
        if finder.find_module(name, package_path):
            return True
    for entry in package_path:
        try:
            # Try the cached finder.
            finder = sys.path_importer_cache[entry]
            if finder is None:
                # Implicit import machinery should be used.
                try:
                    file_, _, _ = imp.find_module(module_name, [entry])
                    if file_:
                        file_.close()
                    return True
                except ImportError:
                    continue
            # Else see if the finder knows of a loader.
            elif finder.find_module(name):
                return True
            else:
                continue
        except KeyError:
            # No cached finder, so try and make one.
            for hook in sys.path_hooks:
                try:
                    finder = hook(entry)
                    # XXX Could cache in sys.path_importer_cache
                    if finder.find_module(name):
                        return True
                    else:
                        # Once a finder is found, stop the search.
                        break
                except ImportError:
                    # Continue the search for a finder.
                    continue
            else:
                # No finder found.
                # Try the implicit import machinery if searching a directory.
                if os.path.isdir(entry):
                    try:
                        file_, _, _ = imp.find_module(module_name, [entry])
                        if file_:
                            file_.close()
                        return True
                    except ImportError:
                        pass
                # XXX Could insert None or NullImporter
    else:
        # Exhausted the search, so the module cannot be found.
        return False

Bu, python programlarken standart sorumu yerine getiriyor: WWDD (Django Ne Yapardı?) Ve oraya
bakmalıydım
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.