Koks yra teisingiausias būdas importuoti savo sukurtus modulius?
Idėja: rašau programą ir grupuoju savo modulius pagal paskirtį skirtinguose kataloguose ir/ar failuose. Norėčiau, kad programa vienodai gerai veiktų betkuriame kompiuteryje. Pirmas Klausimas: Jei noriu, reikalui esant, įsikelti atitinkamą modulį, koks yra geriausias būdas tai padaryti?
Antras Klausimas: Naudojant šį metodą bus nuolat šiukšlinama į python $PATH. Teoriškai, kas kart paleidus programą bus pridedama nauja path reikšmė. Tokiu atveju programai dar net negimus ji jau tampa kenkėjiška.
Trečias Klausimas: Naudojantis šiuo metodu į $PATH gali būti įkeltos dvi ar daugiau nuorodų į modulių katalogus, kur modulių pavadinimai tariamai gali kartotis, taigi Python'as turėtų susipainioti. O gal galima kažkaip nurodyti, kad būtų naudojamas modulis iš būtent to katalogo? (Ši problema nėra opi, daug svarbesni atsakymai į pirmus 2 klausimus)
from moduliuKatalogas.pirmaModuliuGrupe import modulis
Dažniausiai į sys.path nesant rimtam reikalui niekas nieko ten nerašo.
Kitas dalykas, jei nori kurti pernaudojamus modulius, kurie gali būti naudojami keliuose skirtinguose projektuose, reikėtų juos supaketuoti ir toliau naudoti kaip python paketus. Tada python paketavimo sistema pasirūpins tų modulių įkėlimu į sys.path.
Jei moduliai skirtinguose kataloguose (paketuose) pasikartoja, tada imamas tas, kuris yra pirmesnis sys.path sąraše. Kad išvengti tokių pasikartojimų, dažniausiai paketai dedami į tam tikrą projekto su unikaliu pavadinimų vardų erdvę, pavyzdžiui:
Dar sykį perkračiau internetą, ir ką, teko nusivilti - nieko naujo nesužinojau.
Vienintelis lengvas būdas įsikelti savo modulius - prisišiukšlinti, t.y. palikti juos tame pačiame aplanke, kaip ir failas, kuris juos iškviečia..
When you import a module, the Python interpreter searches for the module in the following sequences:
* The current directory.
* If the module isn't found, Python then searches each directory in the shell variable PYTHONPATH.
* If all else fails, Python checks the default path. On UNIX, this default path is normally /usr/local/lib/python/.
Tikrai nenoriu tikėti, kad vienintelė išeitis yra šiukšlinti į $PATH, po to rašyti script'ą, kad tikrinti, ar adresatas jau egzistuoja sąraše. Python gyvuoja jau ne pirmus metus, todėl turėtų būti kažkoks būdas slankioti per aplankus, na bent startinio failo aplinkoje nerti giliau..
Pataisykit, prašau kas nors, nes jau pradedu nusivilti tokiu Python nelankstumu..
Python importavimo mechanizmas veikia labai paprastai ir pakankamai lanksčiai. Į sys.path tau pačiam tikrai nieko nereikia įrašinėti, nes tuo turi rūpintis python paketų valdymo įrankiai.
Pagal nutylėjimą, modulių (arba failų) kuriuos bandai importuoti ieškoma iš eilės visuose sys.path sąraše esančiuose kataloguose. sys.path pagal nutylėjimą pirmoje vietoje turi įtrauktą katalogą, kuriame yra python failas, kuris buvo įvykdytas.
Kaip matai, pirmoje vietoje ieškoma failų iš '/tmp' katalogo, todėl, kad failas kurį iškviečiau '/tmp/boo.py' yra '/tmp' kataloge. Tai reiškia, kad viskas, ką nori importuoti turi būti arba tame pačiame kataloge, kur yra tavo paleistas failas, arba viename iš sys.path katalogų.
Kai įdiegi kokį nors python paketą naudodamasis pip install paketovardas, tada python paketų valdymo sistema, automatiškai sutvarko sys.path kelius, kad tas įdiegtas paketas būtų pasiekiamas.
Dar vienas labai svarbus momentas yra katalogai. Tam, kad katalogas būtų laikomas paketu, tame kataloge turi būti failas (gali būti tuščias) pavadinimu 'init.py'. Kaip suprantu, pas tave kataloguose tokių failų nėra, todėl python galvoja, kad čia paprasti katalogai, o ne python moduliai.
Tavo atveju, reikia sukurti tokius tuščius failus:
Beje, pagal python kodo rašymo taisykels PEP-8, rekomenduojama modulių pavadinimus rašyti iš mažųjų raidžių, tavo atveju 'moduliuKatalogas.pirmaModuliuGrupu' reikėtų keisti arba į trumpesnius pavadinimus (think namespace) arba į tai: 'moduliukatalogas.pirmamoduliugrupe'.
Šiuo atveju, jei katalogas moduliai nėra įtrauktas į sys.path ir programą leidi per moduliai/moduliuKatalogas/pirmaModuliuGrupu/start.py, tada modulio modulis2.py negalėsi niekaip importuoti.
Python'e failų importavimas padarytas taip, kad reali python modulių (.py failų) buvimo vieta yra visiškai nesvarbi, svarbu yra tik tai, kad tie failai atsidurtų viename iš katalogų, išvardintų sys.path sąraše. Toks principas išsprendžia gausybę problemų, tokių kaip importuojamų modulių kelių prefiksavimas ir pan.
Kad nereikėtų sys.path sąrašo koreguoti rankiniu būdu, Python naudoja paketų valdymo sistemą. Jei nori, turėti kažkokius modulių rinkinius, kuriuos planuoji naudoti kelios skirtingose programose, tai tą modulių rinkinį turi tvarkingai supaketuoti ir įdiegti į aplinką kurioje dirbi, kaip python paketą.
Jei nuspręsi savo paketą paviešinti, tai visi Python paketai viešinami čia: http://pypi.python.org/
Naudojantis pip įrankiu, Python paketus gali įdiegti arba į sistemą, arba į uždarą ir izoliuotą virtualenv aplinką. Kuriant programas rekomenduoju visus reikiamus paketus įsidiegti į virtualenv, kad neterštum savo distribucijos aplinkos. Kaip naudotis virtualenv, aprašyta čia: http://www.virtualenv.org/
Kad neatrodytų viskas taip baisiai sudėtinga iliustruosiu komandinės eilutės pavyzdžiais patį paprasčiausią atvejį, kaip pasinaudojant visais šiais aprašytais įrankiais, kad sukurti python paketą, kuriame būtų saugomi bendrai naudojami moduliai ir galiausiai tas modulis būtų realiai panaudotas programoje.
Tarkime noriu sukurti python paketą, kurio paskirtis saugoti funkciją pavadinimu "hello". Tada šį paketą panaudosiu savo programoje ir iškviesiu šią funkciją.
Tada pasinaudodamas virtualenv įrankiu, susikuriu izoliuotą aplinką, kurioje ir kursiu savo paketus ir programas:
virtualenv --no-site-packages env && cd $_
Pasinaudodamas ką tik įdiegtu PasteScript susikuriu naują paketą, kuris teiks funkciją 'hello':
paster create -t basic_package
Įvedus šią komandą atsidarys interaktyvus vedlys, kuris paklaus visko ko reikia kuriant naują paketą. Tai turėtų atrodyti maždaug taip:
Selected and implied templates:
PasteScript#basic_package A basic setuptools-enabled package
Enter project name: hellolib
Variables:
egg: hellolib
package: hellolib
project: hellolib
Enter version (Version (like 0.1)) ['']:
Enter description (One-line description of the package) ['']:
Enter long_description (Multi-line description (in reST)) ['']:
Enter keywords (Space-separated keywords/tags) ['']:
Enter author (Author name) ['']:
Enter author_email (Author email) ['']:
Enter url (URL of homepage) ['']:
Enter license_name (License name) ['']:
Enter zip_safe (True/False: if the package can be distributed as a .zip file) [False]:
Creating template basic_package
Creating directory ./hellolib
Recursing into +package+
Creating ./hellolib/hellolib/
Copying __init__.py to ./hellolib/hellolib/__init__.py
Recursing into docs
Creating ./hellolib/docs/
Copying setup.cfg to ./hellolib/setup.cfg
Copying setup.py_tmpl to ./hellolib/setup.py
Running /usr/bin/python setup.py egg_info
Iš visų užduotų klausimų būtinas tik pirmasis - paketo pavadinimas. Visi kiti atsakymai neprivalomi, galima spausti Enter.
Naujai sukurtas paketas gulės kataloge, tokiu pačiu pavadinimu, kaip ir paketo vardas, mano atveju jis yra 'hellolib'. Paketo katalogo turinys atrodo taip:
Toliau, šiame pakete, faile hellolib/hellolib/init.py sukursiu funkciją pavadinimu 'hello'. Failo turinys turėtų atrodyti taip:
def hello():
print('Sveikas pasauli!')
Toliau, šį naują paketą, su nauja funkcija 'hello' įdiegsiu į izoliuotą aplinką:
(cd hellolib && ../bin/python setup.py develop)
Šiuo atveju paketą įdiegiau taip vadinamu develop režimu, tai reiškia, kad galiu ir toliau keisti paketą jo neįdiegdamas naujai. Taip pat panaudojau izoliuotos aplinkos python'ą, kad šis paketas nebūtų įdiegtas į sistemą. Norint įdiegti šį paketą į sistemą reikėtų įvesti sudo python setup.py install komandą.
Jei veikia, į ekraną turi būti išvesta eilutė su tekstu: „Sveikas pasauli!“.
Galiausiai susikuriam naują programą, kuri naudos šią biblioteką. Programos kodas bus patalpintas start.py faile ir šio failo turinys bus toks:
import hellolib
hellolib.hello()
Galiausiai įvykdau šią programą ir žiūriu kas gaunasi:
bin/python start.py
Sveikas pasauli!
Veikia. Kadangi hellolib yra įdiegtas į virtualenv izoliuotą aplinką, tai jis yra pasiekiamas iš visur, t.y. šią biblioteką nekeičiant sys.path galima importuoti bet kur, svarbu, kad ta programa būtų paleistai per virtualią aplinką.
Apibendrinus, norint gautą tą patį ką aprašiau, reikia suvesti tokias komandas:
Actually, modules are searched in the list of directories given by the variable sys.path which is initialized from the directory containing the input script (or the current directory), PYTHONPATH and the installation- dependent default.
Tai reiškia, kad sys.path iš naujo sukuriamas kas kart paleidus script'ą. Be to buvau įsitikinęs, kad PYTHONPATH ir sys.path yra tas pats daiktas, todėl keičiant vieną keičiasi ir kitas. Dabar, kai pagaliau atsivėrė akys, supratau, kad PYTHONPATH tėra viena sys.path dedamoji, taigi sys.path.append() niekur nešiukšlina.
Dar kartą dėkoju už smulkmeniškumą. Manau, tema oficealiai baigta
Ok. Pabaigai noriu tik pridurti, kad iš tikrųjų praktikoje, rankomis sys.path niekas nekeičia, nes tokiu atveju programos būtų labai nelanksčios ir niekur, išskyrus tavo vieno kompiuterį neveiktų. Todėl ir naudojamas python distulis, kuris pats pasirūpina sys.path turiniu, taip kaip reikia ir kad tai veiktu visiems ir visur.
Viskas, ką tavo programa turi žinoti apie kelius, turėtų apsiriboti tik vien katalogu, kuriame yra visas paketo turinys.
Sveiki,
Koks yra teisingiausias būdas importuoti savo sukurtus modulius?
Idėja: rašau programą ir grupuoju savo modulius pagal paskirtį skirtinguose kataloguose ir/ar failuose. Norėčiau, kad programa vienodai gerai veiktų betkuriame kompiuteryje.
Pirmas Klausimas: Jei noriu, reikalui esant, įsikelti atitinkamą modulį, koks yra geriausias būdas tai padaryti?
Glaustai išdėstysiu, ką pavyko išsiaiškinti.
Jei turiu tokią struktūrą:
Tada, kad įsikelčiau savo modulius, startiniame programos faile turėčiau įrašyti tokias eilutes:
Antras Klausimas: Naudojant šį metodą bus nuolat šiukšlinama į python $PATH. Teoriškai, kas kart paleidus programą bus pridedama nauja path reikšmė. Tokiu atveju programai dar net negimus ji jau tampa kenkėjiška.
Trečias Klausimas: Naudojantis šiuo metodu į $PATH gali būti įkeltos dvi ar daugiau nuorodų į modulių katalogus, kur modulių pavadinimai tariamai gali kartotis, taigi Python'as turėtų susipainioti. O gal galima kažkaip nurodyti, kad būtų naudojamas modulis iš būtent to katalogo? (Ši problema nėra opi, daug svarbesni atsakymai į pirmus 2 klausimus)
Dėkui
Šiaip tai tau reikėtų importuoti taip:
Dažniausiai į sys.path nesant rimtam reikalui niekas nieko ten nerašo.
Kitas dalykas, jei nori kurti pernaudojamus modulius, kurie gali būti naudojami keliuose skirtinguose projektuose, reikėtų juos supaketuoti ir toliau naudoti kaip python paketus. Tada python paketavimo sistema pasirūpins tų modulių įkėlimu į sys.path.
Jei moduliai skirtinguose kataloguose (paketuose) pasikartoja, tada imamas tas, kuris yra pirmesnis sys.path sąraše. Kad išvengti tokių pasikartojimų, dažniausiai paketai dedami į tam tikrą projekto su unikaliu pavadinimų vardų erdvę, pavyzdžiui:
Kažkodėl man nepavyksta
Dar sykį perkračiau internetą, ir ką, teko nusivilti - nieko naujo nesužinojau.

Vienintelis lengvas būdas įsikelti savo modulius - prisišiukšlinti, t.y. palikti juos tame pačiame aplanke, kaip ir failas, kuris juos iškviečia..
Tikrai nenoriu tikėti, kad vienintelė išeitis yra šiukšlinti į $PATH, po to rašyti script'ą, kad tikrinti, ar adresatas jau egzistuoja sąraše. Python gyvuoja jau ne pirmus metus, todėl turėtų būti kažkoks būdas slankioti per aplankus, na bent startinio failo aplinkoje nerti giliau..
Pataisykit, prašau kas nors, nes jau pradedu nusivilti tokiu Python nelankstumu..
Python importavimo mechanizmas veikia labai paprastai ir pakankamai lanksčiai. Į sys.path tau pačiam tikrai nieko nereikia įrašinėti, nes tuo turi rūpintis python paketų valdymo įrankiai.
Pagal nutylėjimą, modulių (arba failų) kuriuos bandai importuoti ieškoma iš eilės visuose sys.path sąraše esančiuose kataloguose. sys.path pagal nutylėjimą pirmoje vietoje turi įtrauktą katalogą, kuriame yra python failas, kuris buvo įvykdytas.
Pavyzdys:
Kaip matai, pirmoje vietoje ieškoma failų iš '/tmp' katalogo, todėl, kad failas kurį iškviečiau '/tmp/boo.py' yra '/tmp' kataloge. Tai reiškia, kad viskas, ką nori importuoti turi būti arba tame pačiame kataloge, kur yra tavo paleistas failas, arba viename iš sys.path katalogų.
Kai įdiegi kokį nors python paketą naudodamasis pip install paketovardas, tada python paketų valdymo sistema, automatiškai sutvarko sys.path kelius, kad tas įdiegtas paketas būtų pasiekiamas.
Dar vienas labai svarbus momentas yra katalogai. Tam, kad katalogas būtų laikomas paketu, tame kataloge turi būti failas (gali būti tuščias) pavadinimu 'init.py'. Kaip suprantu, pas tave kataloguose tokių failų nėra, todėl python galvoja, kad čia paprasti katalogai, o ne python moduliai.
Tavo atveju, reikia sukurti tokius tuščius failus:
Beje, pagal python kodo rašymo taisykels PEP-8, rekomenduojama modulių pavadinimus rašyti iš mažųjų raidžių, tavo atveju 'moduliuKatalogas.pirmaModuliuGrupu' reikėtų keisti arba į trumpesnius pavadinimus (think namespace) arba į tai: 'moduliukatalogas.pirmamoduliugrupe'.
Dėkui už init.py, įkėlus šį failiuką į kiekvieną katalogą, atrodo, pavyksta importuoti norimus modulius tavo nurodytu būdu:
Visgi esant tokiai failų struktūrai:

Kaip start.py faile nurodyti kelią iki modulio modulis2.py?
Šiuo atveju, jei katalogas moduliai nėra įtrauktas į sys.path ir programą leidi per moduliai/moduliuKatalogas/pirmaModuliuGrupu/start.py, tada modulio modulis2.py negalėsi niekaip importuoti.
Python'e failų importavimas padarytas taip, kad reali python modulių (.py failų) buvimo vieta yra visiškai nesvarbi, svarbu yra tik tai, kad tie failai atsidurtų viename iš katalogų, išvardintų sys.path sąraše. Toks principas išsprendžia gausybę problemų, tokių kaip importuojamų modulių kelių prefiksavimas ir pan.
Kad nereikėtų sys.path sąrašo koreguoti rankiniu būdu, Python naudoja paketų valdymo sistemą. Jei nori, turėti kažkokius modulių rinkinius, kuriuos planuoji naudoti kelios skirtingose programose, tai tą modulių rinkinį turi tvarkingai supaketuoti ir įdiegti į aplinką kurioje dirbi, kaip python paketą.
Jei nuspręsi savo paketą paviešinti, tai visi Python paketai viešinami čia: http://pypi.python.org/
Python paketus galima diegti naudojantis pip įrankiu: http://www.pip-installer.org/
Naudojantis pip įrankiu, Python paketus gali įdiegti arba į sistemą, arba į uždarą ir izoliuotą virtualenv aplinką. Kuriant programas rekomenduoju visus reikiamus paketus įsidiegti į virtualenv, kad neterštum savo distribucijos aplinkos. Kaip naudotis virtualenv, aprašyta čia: http://www.virtualenv.org/
Kaip kurti paketus aprašyta čia: http://wiki.python.org/moin/Distutils/Tutorial
Kad būtų paprasčiau kurti Python paketus, gali naudotis paketų kūrimo šablonais. Apie juos informaciją rasi čia: http://pythonpaste.org/script/developer.html#templates
Kad neatrodytų viskas taip baisiai sudėtinga iliustruosiu komandinės eilutės pavyzdžiais patį paprasčiausią atvejį, kaip pasinaudojant visais šiais aprašytais įrankiais, kad sukurti python paketą, kuriame būtų saugomi bendrai naudojami moduliai ir galiausiai tas modulis būtų realiai panaudotas programoje.
Tarkime noriu sukurti python paketą, kurio paskirtis saugoti funkciją pavadinimu "hello". Tada šį paketą panaudosiu savo programoje ir iškviesiu šią funkciją.
Įsidiegiu darbui reikalingas programas:
Tada pasinaudodamas virtualenv įrankiu, susikuriu izoliuotą aplinką, kurioje ir kursiu savo paketus ir programas:
Pasinaudodamas ką tik įdiegtu PasteScript susikuriu naują paketą, kuris teiks funkciją 'hello':
Įvedus šią komandą atsidarys interaktyvus vedlys, kuris paklaus visko ko reikia kuriant naują paketą. Tai turėtų atrodyti maždaug taip:
Iš visų užduotų klausimų būtinas tik pirmasis - paketo pavadinimas. Visi kiti atsakymai neprivalomi, galima spausti Enter.
Naujai sukurtas paketas gulės kataloge, tokiu pačiu pavadinimu, kaip ir paketo vardas, mano atveju jis yra 'hellolib'. Paketo katalogo turinys atrodo taip:
Šiuo atveju paketą įdiegiau taip vadinamu develop režimu, tai reiškia, kad galiu ir toliau keisti paketą jo neįdiegdamas naujai. Taip pat panaudojau izoliuotos aplinkos python'ą, kad šis paketas nebūtų įdiegtas į sistemą. Norint įdiegti šį paketą į sistemą reikėtų įvesti sudo python setup.py install komandą.
Jei veikia, į ekraną turi būti išvesta eilutė su tekstu: „Sveikas pasauli!“.
Galiausiai susikuriam naują programą, kuri naudos šią biblioteką. Programos kodas bus patalpintas start.py faile ir šio failo turinys bus toks:
Galiausiai įvykdau šią programą ir žiūriu kas gaunasi:
Veikia. Kadangi hellolib yra įdiegtas į virtualenv izoliuotą aplinką, tai jis yra pasiekiamas iš visur, t.y. šią biblioteką nekeičiant sys.path galima importuoti bet kur, svarbu, kad ta programa būtų paleistai per virtualią aplinką.
Apibendrinus, norint gautą tą patį ką aprašiau, reikia suvesti tokias komandas:
Dėkui už išsamų atsakymą. Visgi grįžom prie mano pradinio teiginio - modulius reikia įkėlinėti į PATH (arba sys.path) (:
Vat vienintelis svarbus sakinys, kurį pagaliau radau ieškodamas sprendimo:
http://docs.python.org/tutorial/modules.html#the-module-search-path
Tai reiškia, kad sys.path iš naujo sukuriamas kas kart paleidus script'ą. Be to buvau įsitikinęs, kad PYTHONPATH ir sys.path yra tas pats daiktas, todėl keičiant vieną keičiasi ir kitas. Dabar, kai pagaliau atsivėrė akys, supratau, kad PYTHONPATH tėra viena sys.path dedamoji, taigi sys.path.append() niekur nešiukšlina.
Dar kartą dėkoju už smulkmeniškumą. Manau, tema oficealiai baigta
Ok. Pabaigai noriu tik pridurti, kad iš tikrųjų praktikoje, rankomis sys.path niekas nekeičia, nes tokiu atveju programos būtų labai nelanksčios ir niekur, išskyrus tavo vieno kompiuterį neveiktų. Todėl ir naudojamas python distulis, kuris pats pasirūpina sys.path turiniu, taip kaip reikia ir kad tai veiktu visiems ir visur.
Viskas, ką tavo programa turi žinoti apie kelius, turėtų apsiriboti tik vien katalogu, kuriame yra visas paketo turinys.
Tema perkelta iš https://legacy.ubuntu.lt/forum/viewtopic.php?f=11&t=7579