it-swarm-tr.com

Tam yol verilen bir modül nasıl alınır?

Tam yolu verilen bir Python modülünü nasıl yükleyebilirim? Bir yapılandırma seçeneği olduğundan, dosyanın dosya sisteminde herhangi bir yerde bulunabileceğini unutmayın.

922
derfred

Python 3.5+ kullanımı için:

import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.MyClass()

Python 3.3 ve 3.4 için:

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(Bu Python 3.4'de kullanımdan kaldırılmış olmasına rağmen)

Python 2 kullanımı için:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

Derlenmiş Python dosyaları ve DLL'ler için eşdeğer kolaylık işlevleri vardır.

Ayrıca bakınız http://bugs.python.org/issue21436 .

1055
Sebastian Rittau

Sys.path'a yol eklemenin avantajı (imp kullanarak), tek bir pakette birden fazla modül alırken işleri basitleştirmesidir. Örneğin:

import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')

from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch
358
Daryl Spitzer

Ayrıca böyle bir şey yapabilir ve yapılandırma dosyasının Python yükleme yoluna oturduğu dizini ekleyebilir ve ardından dosyanın adını önceden bildiğinizi varsayarsak, bu durumda "config" komutunu kullanabilirsiniz.

Dağınık, ama işe yarıyor.

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config
19
ctcherry

Özel olarak yapılandırma dosyasını içe aktarmak istemiyormuşsunuz gibi (bir sürü yan etkisi ve buna ek olarak ortaya çıkan komplikasyonlar var), sadece onu çalıştırmak ve sonuçta elde edilen isim alanına erişmek isteyebilirsiniz. Standart kütüphane özellikle runpy.run_path şeklinde bir API sağlar:

from runpy import run_path
settings = run_path("/path/to/file.py")

Bu arayüz Python 2.7 ve Python 3.2+ sürümlerinde kullanılabilir.

19
ncoghlan

Kullanabilirsiniz

load_source(module_name, path_to_file) 

imp modülünden yöntem .

16
zuber

@ SebastianRittau’nun harika cevabı (Python> 3.4 için sanırım) biraz değiştirilmiş bir sürümü ile geldim, ki spec_from_loader kullanarak herhangi bir uzantılı bir dosyayı yüklemenizi sağlayacak spec_from_file_location yerine _:

from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader 

spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)

Yolu açık bir şekilde SourceFileLoader olarak kodlamanın avantajı, makine öğesinin, uzantıdaki dosyanın türünü çözmeye çalışmadığıdır. Bu, bu yöntemi kullanarak bir .txt dosyası gibi bir şey yükleyebileceğiniz anlamına gelir, ancak spec_from_file_location.txt içinde olmadığı için yükleyiciyi belirtmeden importlib.machinery.SOURCE_SUFFIXES ile yapamazsınız.

13
Mad Physicist

Yükleme mi, ithalat mı demek istiyorsun?

Sys.path listesini düzenleyebilir, modülünüzün yolunu belirtebilir, ardından modülünüzü alabilirsiniz. Örneğin, şu adresten bir modül verildiyse:

/foo/bar.py

Yapabilirsin:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
12
Wheat

Üst düzey modülünüz bir dosya değilse ama __init__.py ile bir dizin olarak paketlenmişse, kabul edilen çözüm neredeyse işe yarar, ancak tam olarak değil. Python 3.5+ sürümünde aşağıdaki kod gereklidir ('sys.modules' ile başlayan eklenen satırı not edin):

MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module 
spec.loader.exec_module(module)

Bu satır olmadan exec_module çalıştırıldığında, üst düzey __init__.py'nizdeki göreceli ithalatları üst seviye modül adına bağlamaya çalışır - bu durumda "mymodule". Ancak "mymodule" henüz yüklenmedi, bu nedenle "SystemError: Ana modül 'mymodule' yüklü değil, göreceli içe aktarma gerçekleştiremiyor" hatası alırsınız. Bu yüzden yüklemeden önce ismi bağlamanız gerekir. Bunun nedeni göreceli ithalat sisteminin temel değişmezliğidir: "Değişmeyen durum, eğer sys.modules ['spam'] ve sys.modules ['spam.foo'] 'a sahipseniz (yukarıdaki ithalattan sonra olduğu gibi) ), sonuncusu önceki " burada tartışıldığı gibi foo niteliği olarak görünmelidir .

12
Sam Grondahl

Modülünüzü içe aktarmak için, dizinini geçici veya kalıcı olarak ortam değişkenine eklemeniz gerekir.

Geçici

import sys
sys.path.append("/path/to/my/modules/")
import my_module

Kalıcı olarak

.bashrc dosyanıza (linux'ta) aşağıdaki satırı ekleyin ve terminaldeki source ~/.bashrc komutunu çalıştırın:

export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"

Kredi/Kaynak: saarrrr , başka bir yığın değiştirme sorusu

11
Miladiouss

İşte tüm Python sürümlerinde çalışan bazı kodlar, 2.7-3.5 ve hatta diğerleri.

config_file = "/tmp/config.py"
with open(config_file) as f:
    code = compile(f.read(), config_file, 'exec')
    exec(code, globals(), locals())

Test ettim. Çirkin olabilir ama şimdiye kadar tüm sürümlerinde çalışan tek kişi.

11
sorin
def import_file(full_path_to_module):
    try:
        import os
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)
        save_cwd = os.getcwd()
        os.chdir(module_dir)
        module_obj = __import__(module_name)
        module_obj.__file__ = full_path_to_module
        globals()[module_name] = module_obj
        os.chdir(save_cwd)
    except:
        raise ImportError

import_file('/home/somebody/somemodule.py')
10
Chris Calloway

Belirtilen modülü yüklemek için imp.find_module() ve imp.load_module() 'yi kullanabileceğinizi düşünüyorum. Modül adını yoldan ayırmanız gerekecek, yani /home/mypath/mymodule.py yüklemek istiyorsanız, yapmanız gerekenler:

imp.find_module('mymodule', '/home/mypath/')

... ama bu işi halletmeli.

8
Matt

Python modülü test.py oluştur

import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3

Python modülü oluşturma test_check.py

from test import Client1
from test import Client2
from test import test3

Alınan modülü modülden alabiliriz.

3
abhimanyu

Geçerli dizindeki paketlerin bir listesini almak için pkgutil modülünü (özellikle walk_packages method) kullanabilirsiniz. Oradan, istediğiniz modülleri almak için importlib makinesini kullanmak çok önemlidir:

import pkgutil
import importlib

packages = pkgutil.walk_packages(path='.')
for importer, name, is_package in packages:
    mod = importlib.import_module(name)
    # do whatever you want with module now, it's been imported!
3
bob_twinkles

Bu çalışmalı

path = os.path.join('./path/to/folder/with/py/files', '*.py')
for infile in glob.glob(path):
    basename = os.path.basename(infile)
    basename_without_extension = basename[:-3]

    # http://docs.python.org/library/imp.html?highlight=imp#module-imp
    imp.load_source(basename_without_extension, infile)
3
Hengjie

Bunun daha iyi olduğunu söylemiyorum ama tamamlık uğruna, hem python 2 hem de 3'te bulunan exec işlevini önermek istedim. exec, herhangi bir global kapsamda isteğe bağlı kod çalıştırmanıza izin verir, veya bir sözlük olarak verilen dahili bir kapsamda.

Örneğin, "/path/to/module "'da foo() işlevinin bulunduğu bir modülünüz varsa, aşağıdakileri yaparak çalıştırabilirsiniz:

module = dict()
with open("/path/to/module") as f:
    exec(f.read(), module)
module['foo']()

Bu, kodu dinamik olarak yüklediğinizi biraz daha açık hale getirir ve size özel yerleşikler sağlama yeteneği gibi bazı ek güçler verir.

Nitelikler yoluyla erişime sahipseniz, tuşlar yerine sizin için önemliyse, bu tür bir erişim sağlayan, örneğin dünyaya özel bir dikt sınıfı tasarlayabilirsiniz:

class MyModuleClass(dict):
    def __getattr__(self, name):
        return self.__getitem__(name)
3
yoniLavi

Python 3.4'ün bu alanının anlaşılması çok zor görünüyor! Ancak bir başlangıç ​​olarak Chris Calloway'ın kodunu kullanarak biraz hack ile çalışan bir şey almak başardı. İşte temel işlev.

def import_module_from_file(full_path_to_module):
    """
    Import a module given the full path/filename of the .py file

    Python 3.4

    """

    module = None

    try:

        # Get module name and path from full path
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)

        # Get module "spec" from filename
        spec = importlib.util.spec_from_file_location(module_name,full_path_to_module)

        module = spec.loader.load_module()

    except Exception as ec:
        # Simple error printing
        # Insert "sophisticated" stuff here
        print(ec)

    finally:
        return module

Bu Python 3.4'ün kullanım dışı modülleri kullanıyor gibi görünüyor. Nedenini anlamış gibi davranmıyorum, ancak programın içinden çalışıyor gibi görünüyor. Chris'in çözümünün komut satırında çalıştığını ama programın içinden olmadığını gördüm.

3
Redlegjed

Belirli bir dosya adından bir modülü içe aktarmak için yolu geçici olarak uzatabilir ve sistem yolunu sonunda başvuru bloğuna geri yükleyebilirsiniz:

filename = "directory/module.py"

directory, module_name = os.path.split(filename)
module_name = os.path.splitext(module_name)[0]

path = list(sys.path)
sys.path.insert(0, directory)
try:
    module = __import__(module_name)
finally:
    sys.path[:] = path # restore
3
Peter Zhu

Çalışma zamanında paket modüllerini içe aktar (Python tarifi)

http://code.activestate.com/recipes/223972/

###################
##                #
## classloader.py #
##                #
###################

import sys, types

def _get_mod(modulePath):
    try:
        aMod = sys.modules[modulePath]
        if not isinstance(aMod, types.ModuleType):
            raise KeyError
    except KeyError:
        # The last [''] is very important!
        aMod = __import__(modulePath, globals(), locals(), [''])
        sys.modules[modulePath] = aMod
    return aMod

def _get_func(fullFuncName):
    """Retrieve a function object from a full dotted-package name."""

    # Parse out the path, module, and function
    lastDot = fullFuncName.rfind(u".")
    funcName = fullFuncName[lastDot + 1:]
    modPath = fullFuncName[:lastDot]

    aMod = _get_mod(modPath)
    aFunc = getattr(aMod, funcName)

    # Assert that the function is a *callable* attribute.
    assert callable(aFunc), u"%s is not callable." % fullFuncName

    # Return a reference to the function itself,
    # not the results of the function.
    return aFunc

def _get_class(fullClassName, parentClass=None):
    """Load a module and retrieve a class (NOT an instance).

    If the parentClass is supplied, className must be of parentClass
    or a subclass of parentClass (or None is returned).
    """
    aClass = _get_func(fullClassName)

    # Assert that the class is a subclass of parentClass.
    if parentClass is not None:
        if not issubclass(aClass, parentClass):
            raise TypeError(u"%s is not a subclass of %s" %
                            (fullClassName, parentClass))

    # Return a reference to the class itself, not an instantiated object.
    return aClass


######################
##       Usage      ##
######################

class StorageManager: pass
class StorageManagerMySQL(StorageManager): pass

def storage_object(aFullClassName, allOptions={}):
    aStoreClass = _get_class(aFullClassName, StorageManager)
    return aStoreClass(allOptions)
2
user10370

Linux'ta, python betiğiniz dizinde sembolik bir link ekleyerek çalışır.

yani:

ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py

python /absolute/path/to/script/module.pyc oluşturur ve /absolute/path/to/module/module.py içeriğini değiştirirseniz günceller

daha sonra mypythonscript.py dosyasına aşağıdakileri ekleyin

from module import *
2
user2760152

Sizin için imp kullanan bir paket hazırladım. Ben ona import_file diyorum ve bu böyle kullanılıyor:

>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')

Bunu alabilirsiniz:

http://pypi.python.org/pypi/import_file

veya at

http://code.google.com/p/import-file/

2
ubershmekel

oldukça basit bir yol: göreli yoldan içe aktarma dosyası istediğinizi varsayalım ../../MyLibs/pyfunc.py


libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf

Ama bir bekçi olmadan yaparsan, sonunda çok uzun bir yol bulabilirsin.

1
Andrei Keino

importlib paketi yerine imp kullanan basit bir çözüm (Python 2.7 için de test edilmiş olmasına rağmen Python 2.7 için test edilmiştir):

import importlib

dirname, basename = os.path.split(pyfilepath) # pyfilepath: '/my/path/mymodule.py'
sys.path.append(dirname) # only directories should be added to PYTHONPATH
module_name = os.path.splitext(basename)[0] # '/my/path/mymodule.py' --> 'mymodule'
module = importlib.import_module(module_name) # name space of defined module (otherwise we would literally look for "module_name")

Artık, aktarılan modülün ad alanını doğrudan kullanabilirsiniz, şöyle:

a = module.myvar
b = module.myfunc(a)

Bu çözümün avantajı, almak istediğimiz modülün gerçek adını bile bilmemize gerek yok , kodumuzda kullanmak. Bu yararlıdır, örn. Modül yolu yapılandırılabilir bir argüman olduğunda.

1
Ataxias

Bunu işe yarar bir şey bulamadığım için cevap listesine ekledim. Bu, derlenmiş (pyd) python modüllerinin 3.4'te içe aktarılmasını sağlayacaktır:

import sys
import importlib.machinery

def load_module(name, filename):
    # If the Loader finds the module name in this list it will use
    # module_name.__file__ instead so we need to delete it here
    if name in sys.modules:
        del sys.modules[name]
    loader = importlib.machinery.ExtensionFileLoader(name, filename)
    module = loader.load_module()
    locals()[name] = module
    globals()[name] = module

load_module('something', r'C:\Path\To\something.pyd')
something.do_something()
0
David

Bu cevap, Sebastian Rittau'nun şu yorumu yanıtlayan yanıtının bir ekidir: "peki ya modül adınız yoksa?" Bu, bir dosya adı verilen olası python modülü adını almanın hızlı ve kirli bir yoludur - sadece bir __init__.py dosyası içermeyen bir dizin bulana ve ardından bir dosya ismine geri dönene kadar ağacı açar. Python 3.4+ (pylib kullanır), çünkü Py2 kullanıcıları "imp" ya da diğer göreceli ithalat yapmanın diğer yollarını kullanabilirler:

import pathlib

def likely_python_module(filename):
    '''
    Given a filename or Path, return the "likely" python module name.  That is, iterate
    the parent directories until it doesn't contain an __init__.py file.

    :rtype: str
    '''
    p = pathlib.Path(filename).resolve()
    paths = []
    if p.name != '__init__.py':
        paths.append(p.stem)
    while True:
        p = p.parent
        if not p:
            break
        if not p.is_dir():
            break

        inits = [f for f in p.iterdir() if f.name == '__init__.py']
        if not inits:
            break

        paths.append(p.stem)

    return '.'.join(reversed(paths))

İyileştirme için kesinlikle imkanlar var ve isteğe bağlı __init__.py dosyaları başka değişiklikler gerektirebilir, ancak genel olarak __init__.py varsa, bu işin püf noktasıdır.