Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Множественная загрузка модуля


Автор: DProf 3.10.2014, 13:31
Добрый день!

Вопрос скорее теоретический.
Возникла необходимость несколько раз подряд загружать один и тот же модуль. Смысл в том, что в зависимости от переменных окружения (которые изменяются в процессе работы программы) он возвращает разные значения переменных. То есть надо уже загруженный модуль загрузить снова и он вернет другие значения. Какие тут есть пути?

Я так понял, что либо eval "module_code" , либо do "module_path", иного способа делать это нет.

Модуль сторонний, лезть в него не очень... Лучшее решение тут, конечно, функция в самом модуле, которая вернет то что надо в зависимости от переменных окружения. Тогда один раз его загрузить и пользоваться функцией. Но раз разработчик модуля это не предусмотрел, то либо расширять модуль такой функцией, либо несколько раз подряд загружать один и тот же модуль.

Автор: tzirechnoy 3.10.2014, 15:59
Цитата
Какие тут есть пути?


Как минимум -- прекратить называть эту хрень модулем.

А так -- в perldoc -f use и perldoc -f require -- вполне внятным перловым языком описано, что эти команды делают, соответственно, из них понятно -- как это сделать много раз и со своими прибабахами.

Автор: DProf 3.10.2014, 17:59
Цитата

прекратить называть эту хрень модулем

Согласен, переписал его по-человечески. С функцией, о которой писал. Теперь его можно модулем назвать smile и задача решена.

А изучение perldoc -f use и perldoc -f require привело меня лишь к тому, что не обойтись без выяснения пути к файлу и далее eval его кода (как в sub require из perldoc -f require). А то я надеялся на параметр какой то у require, который отменит 
Цитата
 Note that the file will not be included twice under the same specified name. 

Автор: Pfailed 3.10.2014, 21:49
Цитата(DProf @  3.10.2014,  17:59 Найти цитируемый пост)
А то я надеялся на параметр какой то у require, который отменит 

От этого может помочь удаление записи из глобального хеша %INC. Насколько знаю require там и проверяет не загружен ли модуль. Соотвтетственно после "require My::Module" появится запись $INC{"My/Module.pm"}, которую можно delete.
Ещё может оказаться полезным Symbol::delete_package и Class::Unload

Автор: Ihost 7.11.2014, 13:00
Есть две большие разницы между группой конструкций вида require/do и use/no, первые из которых занимаются импортом и первичным исполнением предложенного программного модуля, а вторые отвечают за загрузку и выгрузку структурированного Perl-модуля, в том числе с участием спецификации Exporter
В хорошей реализации ничто не мешает сделать вам локальные вызовы use и no в надлежащем порядке

Автор: arto 7.11.2014, 16:59
# cat > T.pm
package T;
our $internalvar = $ENV{'T'};
1;
^D
# T=10 perl -l
use T; print "use T: $T::internalvar";
$ENV{'T'} = 20;
no T; print "no T: $T::internalvar";
use T; print "use T: $T::internalvar";
^D
use T: 10
no T: 10
use T: 10
#

Автор: Ihost 10.11.2014, 12:44
Да совершенно ожидаемый результат, *включение* модуля действительно выполняется один раз при помощи неявного require, обратить выполнение его невозможно
Действительно же Perl преобразует конструкции типа use Module во включения вида BEGIN { require "Module.pm"; }, именно по этой причине добавления неявного require в BEGIN-обертку, путь для поиска целевых модулей необходимо прописывать тоже в BEGIN-блоке, иначе программа сразу же завершится с ошибкой

Тут дело в другом- штукенция под названием T.pm не совсем модуль, хотя формально и является *умным пакетом*, и возвращает единицу
НО самое главное в модуле- это механизм экспорта элементов, который и основывается на use/no и модуле Exporter
Здесь же этого нет, следовательно модуль никак фактически не реагирует на use/no, с таким же успехом можно было написать BEGIN {require "T.pm"; }

Автор: Ihost 10.11.2014, 13:43
И да полный ответ с технической точки зрения, чтобы не осталось вопросов по реализации, для простоты два файла в одной директории
Файл MyProgram.pl
Код

#!/usr/bin/perl
eval("use MyModule;");
print "Hello world 1 \n";
eval("no MyModule;");
print "Hello world 2 \n";
eval("use MyModule; ");
print "Hello world 3 \n";
exit;

Файл MyModule.pm
Код

#!/usr/bin/perl
package MyModule;
print "Hello from module \n";
sub import {print "Import from module \n";
}
sub unimport {print "Unimport from module \n";
}
1;

Да очевидно все вызовы use/no в текущем контексте всплывают в начало потока исполнения, поэтому чтобы оставить их на своем месте, добавлена функция eval; можно использовать и другие условные конструкции


С архитектурной точки зрения важно просто помнить и понимать, что является модулем в Perl-философии, а что нет
По аналогии как если в вашей программе есть классы, не значит, что это объектно-ориентированное программирование



Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)