python. перекрёстный импорт.

Phoenix

main.py
 
from m1 import get_username
from m2 import calc_profit


print get_username
print calc_profit

m2.py
 from m2 import some_surname



def calc_income:
return 2




def get_username:
return 'Alex' + some_surname

m2.py
 from m1 import calc_income



def calc_profit:
return calc_income/2


def some_surname:
return 'Black'

исполняем:
F:\igor\apps\devel\python\importtest>python run.py
Traceback (most recent call last):
File "run.py", line 16, in <module>
from m1 import get_username
File "F:\igor\apps\devel\python\importtest\m1.py", line 1, in <module>
from m2 import some_surname
File "F:\igor\apps\devel\python\importtest\m2.py", line 1, in <module>
from m1 import calc_income
ImportError: cannot import name calc_income

что делать-то?
На практике было так. в одном файле лежит список констатнт.
в некотором файле utils.py есть функция, которая проверяет, является ли значение поля допустимым (кроме всего прочего делает from ... import.... из файла со списком констант)
ну и сам файл где лежит список констант в одной функции использует вспомогательную улилиту из utils.py
Что я делаю не так?

oliver11

Не питонист, но первое, что приходит в голову — импортить внутри функции, которой надо то, что импортится.

Commandor

Что я делаю не так?
Перекрестно импортируешь.
Если очень хочется, то можно делать так:

def calc_profit:
from m1 import calc_income
return calc_income/2

Phoenix

так работает. :)
Почему не работает так, как я написал? Зачем так сделали?
UPD: примерно разобрался, как работает. Хотя вроде это не очень очевидное поведение.

conv3rsje

Зачем так сделали?
Ибо делать чтоб это работало - весьма геморройно.
Собственно я даже не особо понимаю как это можно сделать.
В сях, например, это решается #ifdef'ами в заголовках или #pramga once,
но там заголовочные файлы не интерпретируются. При этом думаю можно
придумать конструкцию которая и там работать не будет.

Phoenix

ну вот так работает
 
print "INIT m1"

def calc_income:
return 2

from m2 import some_surname
def get_username:
return 'Alex' + some_surname

 
print "INIT m1"



def some_surname:
return 'Black'

from m1 import calc_income
def calc_profit:
return calc_income/2

Т.е. проблема ровно в том, что в тот момент, когда m2 запрашивается функцию из m1, m1 не доинициализировался до нужной функции
У меня просто было ошибочное представление, что модуль - это не скрипт, который исполняется построчно, а некоторое неупорядочное множество разных сущностей (объявление функций, переменных и т.д.)

conv3rsje

У меня просто было ошибочное представление, что модуль - это не скрипт, который исполняется построчно, а некоторое неупорядочное множество разных сущностей (объявление функций, переменных и т.д.)
И как ты себе представляешь реализацию этого? Питон - интерпретируемый язык, поэтому
пока ты не добрался до объявления нужных вещей, их у тебя просто не существует.
Вообще самый разумный совет был с импортом внутри функции

Phoenix

ну не лезть туда. пока не требуют.
пока вызов не сделали, оставить заглушку. А когда попросят вызвать и, если не повезло, падать в NameError. :grin:

conv3rsje

ну не лезть туда. пока не требуют.
модуль может не только что-то свое выдавать, но и модифицировать чужое или что-нибудь полезное делать
например, при загрузке рассчитывать какие-нибудь статические значения, словари там или еще что
или monkey patching, который люто рулит
да и синтаксис неплохо было бы проверить
так что не выйдет ничего не делать при импорте

serega1604

в той же жабе это как-то работает. в чем глобальное отличие жабы от питона, из-за которого так сделать нельзя?

conv3rsje

в чем глобальное отличие жабы от питона, из-за которого так сделать нельзя?
ну насколько я понимаю, проблема в том что выражение
from module import obj

не может быть нормально обработано, пока мы не прочитали _весь_ module и все его вложенности
в яве всё таки более статические типы/имена переменных - если уж что-то объявили то не можем через
несколько строчек передумать, забыть про это и переобъявить заново
upd
Глобальное отличие, конечно же, в том что ява - компилируемый язык

Phoenix

не может быть нормально обработано,

в моём примере обработалось. Это баг? ведь потом могло быть переопределение функции.
Если так размышлять, можно сказать, что нельзя ничего импортировать, т.к. в будущем кто-то что-то может изменить.

conv3rsje

в моём примере обработалось. Это баг? ведь потом могло быть переопределение функции.
Может быть переопределно. А может и не быть.
Это не баг, это побочные эффекты механизма загрузки модулей.
Поскольку 'import module' сначала лезет в список уже загруженных и оттуда пытается взять,
в момент вызова второго импорта в первом уже прописаны нужные значения.
Собственно проблема в изрядной степени надуманная, циклические зависимости вообще зло, независимо от языка.

yroslavasako

в той же жабе это как-то работает. в чем глобальное отличие жабы от питона, из-за которого так сделать нельзя?
отличие в том, что питон - интерпретеруемый. В яве ты объявляешь класс. В питоне ты при инициализации ты создаёшь классы. И всё остальное тоже: функции, константы - являются объектами, создаваемыми внутри очень большой инициализурующей модуль процедуры при её запуске, происходящем при загрузке модуля.

serega1604

>отличие в том, что питон - интерпретеруемый.
Настолько же, насколько и ява (ну кроме может того момента, что нет более-менее распространенного интерпретатора, понимающего сразу исходный код - распространенные понимают обычно байткод.
И в питоне и в яве есть байткод, и там и там есть jit. в чем разница-то?
>В яве ты объявляешь класс. В питоне ты при инициализации ты создаёшь классы.
В яве можно в рантайме поменять существующий класс.
Более того, при компиляции в байткод у тебя может быть одна версия класса, а во время интерпретации - другая, и ты легко словишь в рантайме Error из-за отсутствия метода в классе.

tipnote

И в питоне и в яве есть байткод, и там и там есть jit. в чем разница-то?
Хде есть jit?

tipnote

Ну и вообще терзают меня смутные мысли, что товарищ Гвидо придерживается точки зрения, что некоторые сомнительные фичи не стоят усложнения интерпретатора. И учитывая почти полное отсутствие рантайм оптимизаций в мейнстрим интерпретаторах, это точка зрения может иметь еще и довод по производительности.

Phoenix

здесь проблема в том, что у тебя нет "исходного" состояния, которое получается после компиляции. Ты начинаешь с чистого листа.
И "import SomeNameSpace" реально что-то делает, в отличии от "using SomeNameSpace" (или как там в джаве)
Грубо говоря. Если в модуле тело функции выкачивается из инета, то "import SomeNameSpace" может сломаться, когда инет не работает, а может и нормально отработать.

serega1604

>Хде есть jit?
в питоне и яве.

serega1604

>здесь проблема в том, что у тебя нет "исходного" состояния, которое получается после компиляции. Ты начинаешь с чистого листа.
даже после компиляции в байткод?
>Грубо говоря. Если в модуле тело функции выкачивается из инета, то "import SomeNameSpace" может сломаться, когда инет не работает, а может и нормально отработать.
вообще говоря, тело класса в яве тоже может выкачиваться из инета, только этим почти никто не пользуется. так в чем глобальная разница-то?

conv3rsje

даже после компиляции в байткод?
Если я ничего не путаю, питоновский байткод всего лишь более машинночитаемый вид исходников.
При его загрузке происходит всё то же самое, кроме синтаксического разбора.
По крайней мере из него прекрасно восстанавливается обычный код (не всегда, правда, если всякие корявые случаи)
Как правильно уже здесь отметили в питоне практически нет компиляции, так что каждая загрузка требует обработки и рюхания кода.
Вот например типичный кусок:
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO

Это запросто может быть в модуле в корне, так что при его загрузке мы получим разные результаты в зависимости от окружения.

serega1604

да я уже побаловался с этим вашим питоном и понял, что у вас беда с ссылками на функции (даже вспомнил, что слышал об этом раньше поэтому видимо и импорт такой кривой.

Dmitriy82

По-моему, самое правильное в такой ситуации

import m1
... m1.whatever ...

Доступ к атрибутам модуля будем происходить именно там, где они нужны.

yroslavasako

И в питоне и в яве есть байткод, и там и там есть jit. в чем разница-то?
Хде есть jit?
PyPy за счёт jitа догнало и обогнало на некоторых тестах CPython

tipnote

PyPy за счёт jitа догнало и обогнало на некоторых тестах CPython
Это несерьезно. Обсуждать джит компилятор не продакшн системы.
Теоретически можно написать все что угодно, вопрос в сроках-целесообразности. Но до сих пор в питоне джит компилятора, которым можно пользоваться, нет.
Оставить комментарий
Имя или ник:
Комментарий: