سؤال

كيف يمكنني تحميل بيثون وحدة نظرا كامل الطريق ؟ علما أن الملف يمكن أن تكون في أي مكان في نظام الملفات ، كما يتم تكوين الخيار.

هل كانت مفيدة؟

المحلول

بايثون 3.5+ استخدام:

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()

بايثون 3.3 و 3.4 استخدام:

from importlib.machinery import SourceFileLoader

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

(على الرغم من أن هذا قد تم إهمال في بايثون 3.4.)

بايثون 2 الاستخدام:

import imp

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

هناك ما يعادل الراحة وظائف جمعت الثعبان ملفات Dll.

انظر أيضا http://bugs.python.org/issue21436.

نصائح أخرى

الاستفادة من إضافة مسار sys.مسار (أكثر من استخدام عفريت) هو أنه يبسط الأمور عند استيراد أكثر من وحدة واحدة من حزمة واحدة.على سبيل المثال:

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

يمكنك أيضا أن تفعل شيئا من هذا القبيل و إضافة الدليل أن ملف التكوين يجلس في بيثون مسار الحمل, و من ثم القيام العادي الاستيراد ، على افتراض انك تعرف اسم الملف في وقت مبكر ، في هذه الحالة "التكوين".

فوضوي ، لكنه يعمل.

configfile = '~/config.py'

import os
import sys

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

import config

يبدو أنك لا تريد على وجه التحديد استيراد ملف التكوين (الذي له الكثير من الآثار الجانبية تعقيدات إضافية المشاركة) ، أنت فقط تريد تشغيله, و تكون قادرة على الوصول إلى الناتجة مساحة الاسم.المكتبة القياسية يوفر API خصيصا في شكل runpy.run_path:

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

أن واجهة هو متاح في بايثون 2.7 و الثعبان 3.2+

يمكنك استخدام

load_source(module_name, path_to_file) 

طريقة من عفريت وحدة.

إذا كان الخاص بك أعلى مستوى الوحدة هو ليس ملف ولكن يتم حزم مع الدليل __init__.py ثم الحل المقبول يعمل تقريبا ولكن ليس تماما.في بيثون 3.5+ التعليمة البرمجية التالية الحاجة (ملاحظة تم إضافة السطر الذي يبدأ بـ 'sys.وحدات'):

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)

دون هذا الخط عند exec_module يتم تنفيذه ، فإنه يحاول ربط نسبة الواردات في المستوى الأعلى الخاص بك __init__.py إلى المستوى العلوي اسم الوحدة النمطية -- في هذه الحالة "mymodule".ولكن "mymodule" لا يتم تحميله بعد ذلك سوف تحصل على خطأ "SystemError:الأم وحدة 'mymodule' لا تحميل لا يمكن أن تؤدي نسبة الاستيراد".لذلك تحتاج إلى ربط اسم قبل تحميله.والسبب في هذا هو الأساسية ثابتة النسبية نظام الاستيراد:"إن الثابت من عقد هو أنه إذا كان لديك sys.وحدات['spam'] و sys.وحدات['spam.فو'] (كما تفعل بعد فوق استيراد), هذا الأخير يجب أن تظهر كما فو سمة من السابق" كما نوقش هنا.

وقد تأتي مع نسخة معدلة قليلا من @SebastianRittau رائع الإجابة (بايثون > 3.4 أعتقد) ، والتي سوف تسمح لك لتحميل الملفات مع أي تمديد وحدة نمطية باستخدام spec_from_loader بدلا من spec_from_file_location:

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)

ميزة الترميز المسار في صريح SourceFileLoader هو أن الآلات لن نحاول معرفة نوع الملف من امتداد.هذا يعني أنه يمكنك تحميل ما يشبه .txt الملف باستخدام هذا الأسلوب, لكن أنت لا تستطيع أن تفعل ذلك مع spec_from_file_location دون تحديد محمل لأن .txt ليس في importlib.machinery.SOURCE_SUFFIXES.

هنا بعض التعليمات البرمجية التي يعمل في جميع إصدارات بيثون من 2.7-3.5 وربما حتى الآخرين.

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

اختبرته.قد تكون قبيحة ولكن حتى الآن هو الوحيد الذي يعمل في جميع الإصدارات.

استيراد الوحدة النمطية الخاص بك, تحتاج إلى إضافة الدليل إلى متغير البيئة ، إما مؤقتا أو بشكل دائم.

مؤقتا

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

بشكل دائم

إضافة السطر التالي إلى ملف .bashrc الملف (في لينكس) و excecute source ~/.bashrc في الطرفية:

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

الائتمان/المصدر: saarrrr, آخر stackexchange السؤال

هل يعني الحمل أو الاستيراد ؟

يمكنك التعامل مع sys.مسار قائمة تحديد مسار الوحدة النمطية الخاص بك ، ثم استيراد الوحدة النمطية الخاص بك.على سبيل المثال, نظرا الوحدة في:

/foo/bar.py

هل يمكن أن تفعل:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
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')

أعتقد يمكنك استخدام imp.find_module() و imp.load_module() تحميل الوحدة النمطية المحددة.سوف تحتاج إلى تقسيم اسم الوحدة النمطية عن الطريق ، أيإذا أردت تحميل /home/mypath/mymodule.py سوف تحتاج إلى القيام به:

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

لكن ينبغي أن الحصول على هذه المهمة.

هذا يجب أن تعمل

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)

يمكنك استخدام pkgutil وحدة (على وجه التحديد walk_packages طريقة) للحصول على قائمة من الحزم في الدليل الحالي.من هناك انها تافهة استخدام importlib ماكينات استيراد وحدات تريد:

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.4 يبدو أن مضنية للغاية أن نفهم!ولكن مع قليل من التقطيع باستخدام رمز من كريس كالواي كبداية تمكنت من الحصول على شيء من العمل.هنا هو الوظيفة الأساسية.

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

ويبدو أن الاستخدام غير مستنكر وحدات من بايثون 3.4.أنا لا أدعي أن نفهم لماذا ، ولكن يبدو أن العمل من داخل البرنامج.وجدت كريس الحل عملت على سطر الأوامر ولكن ليس من داخل البرنامج.

أنا لا أقول أن هذا هو أفضل, ولكن من أجل اكتمال أردت أن توحي exec وظيفة متوفرة في كل بيثون 2 و 3.exec يسمح لك لتنفيذ قانون تعسفي في أي نطاق عالمي ، أو في داخلي نطاق توفير القاموس.

على سبيل المثال, إذا كان لديك وحدة تخزين في "/path/to/module"مع وظيفة foo(), هل يمكن تشغيله عن طريق القيام بما يلي:

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

هذا يجعل من قليلا أكثر وضوحا أنك التحميل رمز حيوي و تمنحك بعض الطاقة الإضافية ، مثل القدرة على تقديم مخصص builtins.

وإذا كان الوصول من خلال سمات بدلا من المفاتيح هو مهم بالنسبة لك, يمكنك تصميم مخصص ديكت الفئة globals أن يوفر هذا الوصول ، على سبيل المثال:

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

استيراد وحدة من اسم الملف مؤقتا يمكنك تمديد المسار واستعادة مسار النظام في النهاية كتلة المرجع:

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

إنشاء وحدة بيثون test.py

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

إنشاء وحدة بيثون test_check.py

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

يمكننا الاستيراد المستوردة وحدة من وحدة.

أنا قدمت حزمة يستخدم imp بالنسبة لك.أنا أسميها import_file و هذا هو كيفية استخدامها:

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

يمكنك الحصول على ذلك في:

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

أو في

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

استيراد حزمة وحدات في وقت التشغيل (الثعبان وصفة)

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)

في لينكس ، إضافة ارتباط رمزي في الدليل الخاص بك بيثون السيناريو قائم يعمل.

أي:

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

بيثون خلق /absolute/path/to/script/module.pyc و سيتم تحديث هذا إذا قمت بتغيير محتويات /absolute/path/to/module/module.py

ثم ما يلي في mypythonscript.py

from module import *

بسيط جدا الطريقة:افترض أنك تريد استيراد ملف مع مسار نسبي ../../MyLibs/pyfunc.py


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

ولكن إذا كنت تجعل من دون حارس يمكنك الحصول أخيرا على الطريق الطويل جدا

الحل بسيط باستخدام importlib بدلا من imp حزمة (اختبار بايثون 2.7, على الرغم من أنه ينبغي العمل من أجل بيثون 3 أيضا):

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")

الآن يمكنك مباشرة استخدام مساحة الاسم المستوردة وحدة, مثل هذا:

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

ميزة هذا الحل هو أن لا تحتاج حتى إلى معرفة الاسم الفعلي وحدة ونود أن استيراد, بغية استخدامه في التعليمات البرمجية.هذا هو مفيدة مثلفي حالة مسار الوحدة هو شكلي الحجة.

هذا إضافة إلى قائمة من الأجوبة كما لم أتمكن من العثور على أي شيء يعمل.هذا سوف يسمح الواردات من تجميع (pyd) وحدات بيثون في 3.4:

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()

هذا الجواب هو تكملة سيباستيان Rittau الجواب ردا على تعليق:"ولكن ماذا لو كنت لا تملك وحدة اسمها؟" هذا هو وسيلة سريعة وقذرة من الحصول على الأرجح بيثون وحدة الاسم اسم الملف فقط ترتفع شجرة حتى يجد الدليل دون __init__.py الملف ومن ثم يتحول ذلك إلى اسم الملف.بايثون 3.4+ (يستخدم pathlib) ، الأمر الذي يجعل الشعور منذ Py2 الناس يمكن استخدام "عفريت" أو طرق أخرى من نسبة الواردات:

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))

هناك بالتأكيد إمكانيات التحسين ، الاختياري __init__.py الملفات قد تتطلب تغييرات أخرى, ولكن إذا كان لديك __init__.py عموما هذا لا حيلة.

أفضل طريقة أعتقد من الوثائق الرسمية (29.1.عفريت — الوصول إلى استيراد الداخلية):

import imp
import sys

def __import__(name, globals=None, locals=None, fromlist=None):
    # Fast path: see if the module has already been imported.
    try:
        return sys.modules[name]
    except KeyError:
        pass

    # If any of the following calls raises an exception,
    # there's a problem we can't handle -- let the caller handle it.

    fp, pathname, description = imp.find_module(name)

    try:
        return imp.load_module(name, fp, pathname, description)
    finally:
        # Since we may exit via an exception, close fp explicitly.
        if fp:
            fp.close()
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top