Импорт из встроенной библиотеки при наличии модуля с таким же именем

Ситуация: - В моей папке project_folder называется модуль - Я хотел бы использовать встроенный класс Calendar из библиотек Python - Когда я использую календарь календаря импорта, он жалуется, потому что пытается загрузить из моего модуля.

Я сделал несколько поисков, и я не могу найти решение моей проблемы.

Любые идеи без переименования моего модуля?

Ответ 1

На самом деле, решение этого довольно просто, но реализация всегда будет немного хрупкой, поскольку она зависит от внутренних механизмов механизма импорта python, и они могут быть изменены в будущих версиях.

(следующий код показывает, как загружать как локальные, так и нелокальные модули и то, как они могут сосуществовать)

def import_non_local(name, custom_name=None):
    import imp, sys

    custom_name = custom_name or name

    f, pathname, desc = imp.find_module(name, sys.path[1:])
    module = imp.load_module(custom_name, f, pathname, desc)
    f.close()

    return module

# Import non-local module, use a custom name to differentiate it from local
# This name is only used internally for identifying the module. We decide
# the name in the local scope by assigning it to the variable calendar.
calendar = import_non_local('calendar','std_calendar')

# import local module normally, as calendar_local
import calendar as calendar_local

print calendar.Calendar
print calendar_local

Лучшее решение, если это возможно, состоит в том, чтобы не называть ваши модули с тем же именем, что и имена стандартной библиотеки или встроенных модулей.

Ответ 2

Изменение имени вашего модуля не требуется. Скорее вы можете использовать absolute_import, чтобы изменить поведение импорта. Например, stem/socket.py Я импортирую модуль сокета следующим образом:

from __future__ import absolute_import
import socket

Это работает только с Python 2.5 и выше; это позволяет поведение, которое по умолчанию используется в Python 3.0 и выше. Пилинт будет жаловаться на код, но он совершенно прав.

Ответ 3

Единственный способ решить эту проблему - захватить внутреннее импортное оборудование самостоятельно. Это непросто и чревато опасностью. Вы должны избегать огненного маяка с гравием любой ценой, потому что опасность слишком опасна.

Вместо этого переименуйте свой модуль.

Если вы хотите узнать, как захватить внутреннюю машину импорта, вот где вы можете узнать, как это сделать:

Иногда есть веские причины, чтобы попасть в эту опасность. Причина, по которой вы даете, не среди них. Переименуйте свой модуль.

Если вы возьмете опасный путь, одна из проблем, с которыми вы столкнетесь, заключается в том, что при загрузке модуля он заканчивается "официальным именем", поэтому Python может избежать необходимости анализировать содержимое этого модуля заново. Отображение "официального имени" модуля самому объекту модуля можно найти в sys.modules.

Это означает, что если вы import calendar в одном месте, любой импортируемый модуль будет считаться модулем с официальным именем calendar и всеми другими попытками import calendar в другом месте, в том числе в другом коде, из основной библиотеки Python, получит этот календарь.

Возможно, можно спроектировать импортера клиента, используя модуль imputil в Python 2.x, из-за чего модули, загруженные с определенных путей, выглядят сначала импортировали модули, которые они импортировали в чем-то, кроме sys.modules, или что-то в этом роде. Но это очень волосатое дело, и в любом случае это не будет работать в Python 3.x.

Существует очень уродливая и ужасная вещь, которую вы можете сделать, что не связано с подключением механизма импорта. Это то, чего вы, вероятно, не должны делать, но это, скорее всего, будет работать. Он превращает ваш модуль calendar в гибрид системного календарного модуля и вашего модуля календаря. Благодаря Boaz Yaniv для скелета функции, которую я использую. Поместите это в начало вашего файла calendar.py:

import sys

def copy_in_standard_module_symbols(name, local_module):
    import imp

    for i in range(0, 100):
        random_name = 'random_name_%d' % (i,)
        if random_name not in sys.modules:
            break
        else:
            random_name = None
    if random_name is None:
        raise RuntimeError("Couldn't manufacture an unused module name.")
    f, pathname, desc = imp.find_module(name, sys.path[1:])
    module = imp.load_module(random_name, f, pathname, desc)
    f.close()
    del sys.modules[random_name]
    for key in module.__dict__:
        if not hasattr(local_module, key):
            setattr(local_module, key, getattr(module, key))

copy_in_standard_module_symbols('calendar', sys.modules[copy_in_standard_module_symbols.__module__])

Ответ 4

Я хотел бы предложить свою версию, которая представляет собой комбинацию решения Boaz Yaniv и Omnifarious. Он будет импортировать системную версию модуля с двумя основными отличиями от предыдущих ответов:

  • Поддерживает "точную" нотацию, например. package.module
  • Является заменой замены для оператора импорта на системных модулях, то есть вам просто нужно заменить эту одну строку, и если уже есть вызовы, выполняемые в модуле, они будут работать как-есть

Поместите это где-нибудь доступным, чтобы вы могли его вызвать (у меня есть мой файл __init__.py):

class SysModule(object):
    pass

def import_non_local(name, local_module=None, path=None, full_name=None, accessor=SysModule()):
    import imp, sys, os

    path = path or sys.path[1:]
    if isinstance(path, basestring):
        path = [path]

    if '.' in name:
        package_name = name.split('.')[0]
        f, pathname, desc = imp.find_module(package_name, path)
        if pathname not in __path__:
            __path__.insert(0, pathname)
        imp.load_module(package_name, f, pathname, desc)
        v = import_non_local('.'.join(name.split('.')[1:]), None, pathname, name, SysModule())
        setattr(accessor, package_name, v)
        if local_module:
            for key in accessor.__dict__.keys():
                setattr(local_module, key, getattr(accessor, key))
        return accessor
    try:
        f, pathname, desc = imp.find_module(name, path)
        if pathname not in __path__:
            __path__.insert(0, pathname)
        module = imp.load_module(name, f, pathname, desc)
        setattr(accessor, name, module)
        if local_module:
            for key in accessor.__dict__.keys():
                setattr(local_module, key, getattr(accessor, key))
            return module
        return accessor
    finally:
        try:
            if f:
                f.close()
        except:
            pass

Пример

Я хотел импортировать mysql.connection, но у меня был локальный пакет, уже называемый mysql (официальные утилиты mysql). Поэтому, чтобы получить соединитель из системного пакета mysql, я заменил это:

import mysql.connector

При этом:

import sys
from mysql.utilities import import_non_local         # where I put the above function (mysql/utilities/__init__.py)
import_non_local('mysql.connector', sys.modules[__name__])

Результат

# This unmodified line further down in the file now works just fine because mysql.connector has actually become part of the namespace
self.db_conn = mysql.connector.connect(**parameters)

Ответ 5

Измените путь импорта:

import sys
save_path = sys.path[:]
sys.path.remove('')
import calendar
sys.path = save_path