__file__ не існує в блокноті Jupyter


83

Я перебуваю на сервері Jupyter Notebook (v4.2.2) з Python 3.4.2 і хочу використовувати глобальне ім’я __file__, оскільки ноутбук буде клоновано від інших користувачів, і в одному розділі мені доведеться запустити:

def __init__(self, trainingSamplesFolder='samples', maskFolder='masks'):
    self.trainingSamplesFolder = self.__getAbsPath(trainingSamplesFolder)
    self.maskFolder = self.__getAbsPath(maskFolder)

def __getAbsPath(self, path):
    if os.path.isabs(path):
        return path
    else:
        return os.path.join(os.path.dirname(__file__), path)

У __getAbsPath(self, path)перевіряє , якщо pathпари є відносним або абсолютним шляхом і повертають абсолютну версію path. Тож я можу pathбезпечно використовувати повернене пізніше.

Але я отримую помилку

NameError: ім'я '__file__'не визначено

Я шукав цю помилку в Інтернеті і знайшов "рішення", яке мені краще використовувати sys.argv[0], але print(sys.argv[0])повертається

/usr/local/lib/python3.4/dist-packages/ipykernel/__main__.py

Але має бути правильне розташування зошита /home/ubuntu/notebooks/.

Дякую за посилання. Як отримати поточну назву блокнота IPython від Martijn Pieters (коментарі), остання відповідь (не прийнята) відповідає моїм потребам:

print(os.getcwd())

/ home / ubuntu / notebooks


2
__file__стосується модулів та скриптів Python , а не ноутбуків. Знайдені вами відповіді тут не застосовуються.
Мартін Пітерс

Відповіді:


58

Якщо ви хочете отримати шлях до каталогу, в якому запущений ваш скрипт, я настійно рекомендую використовувати

os.path.abspath('')

Переваги

  • Це працює від Jupyter Notebook
  • Це працює від REPL
  • Для цього не потрібен шлях до Python 3.4

Зверніть увагу, що одним із сценаріїв, де __file__є перевага, є виклик python з каталогу A, але запуск скрипта в каталозі B. У цьому випадку, а також більшість інших методів поверне A, а не B. Однак для Jupyter notbook ви завжди отримуєте папку для.ipyn файлу замість каталогу, звідки ви запустили jupyter notebook.


2
Для мене це не працює. Натомість я отримую "робочий каталог", коли я запускаю блокнот із паперовою фабрикою.
untidyhair

Це дивно. У моєму тестуванні всі 3 сценарії працюють. Чи може це статися через фабрику (я не знайома з нею)?
Shital Shah

3
@Shital, untidyhair - це правильно. Це, як і інша пропозиція від mab нижче, НЕ працює. Це просто дає вам привід.
зародок

20

__file__ може бути недоступним для вас, але ви можете отримати поточну папку, в якій ваш блокнот знаходиться по-різному, насправді.

У глобальних змінних є сліди, якщо ви зателефонуєте, globals()ви побачите, що є елемент із ключем _dh, який може вам допомогти. Ось як мені вдалося завантажити data.csvфайл, який знаходиться в тій же папці, що і мій блокнот:

import os

current_folder = globals()['_dh'][0]

# Calculating path to the input data
data_location = os.path.join(current_folder,'data.csv')

2
Ого, вітаю @shytikov, ваш метод справді працює і повинен бути найкращою відповіддю. Ви знайшли метод, який дозволяє уникнути потворних хаків JS. Велике, велике спасибі. Тепер, якби ми могли отримати спосіб отримати назву блокнота ...
зародок

Схоже, це працює в Notebook, але не в звичайному інтерпретаторі Python (принаймні при імпорті як модуль). Я перемикаюся між використанням ядер Jupyter та звичайним інтерпретатором Python, тому мені потрібно щось, що працює на обох. Я думаю, що я буду вдаватися до змінної середовища.
Kyle Barron

Це працює для мене як в JupyterLab, так і в Pycharm, тоді як інші пропозиції ні.
aimfeld

19

У сучасному Python (v3.4 +) ми можемо використовувати pathlib, щоб отримати каталог ноутбука:

from pathlib import Path

cwd = Path().resolve()
# cwd == PosixPath('/path/to/this/jupyter/ipynb/file's/directory/')

# or this way, thanks @NunoAndré:
cwd = Path.cwd()
# cwd == PosixPath('/path/to/this/jupyter/ipynb/file's/directory/')



Оновлення

@ShitalShah Я не можу відтворити помилку, про яку ви повідомляєте. Здається, блокнот Jupyter працює нормально, незалежно від поточного робочого каталогу, який було запущено.

Приклад: файл ~/dir1/dir2/untitled.ipynbта блокнот Jupyter розпочато в ~/dir1:

Зошит Юпітера розпочато в ~ / dir1

Блокнот Юпітера розпочато в ~/dir1/dir2:

Блокнот Юпітера розпочато з ~ / dir1 / dir2


1
На жаль, це зламається, якщо ви розпочали команду блокнота Jupyter з батьківської папки
Shital Shah

@ShitalShah, будь ласка, дивіться оновлену відповідь. Можливо, ви можете пояснити, яка проблема ви відчуваєте.
МАБ

1
Будь ласка, проігноруйте мій коментар. Ви праві, що це працює в Jupyter Notebook, а також REPL, але є інший спосіб, який не вимагає Python 3.4 pathlib, і я також додав цю відповідь.
Shital Shah

2
Pathмає метод класу саме для цього:Path.cwd()
Нуно Андре

3
@mac, це НЕ працює. Якщо ви зміните cwd у своєму блокноті, то повторно запустіть цю клітинку, це дасть вам новий cwd, а не місце розташування notbook. Це дуже відсутня функція в блокноті Jupyter. Мені доводиться вдаватися до хакерства за участю Javascript. Який ПІТА.
зародок

16

Неможливо знайти шлях до зошита. Можливо, ви знайдете спосіб отримати його, який працює лише в одному середовищі (наприклад os.getcwd()), але це не обов’язково буде працювати, якщо ноутбук завантажується іншим способом.

Натомість спробуйте записати зошит так, щоб йому не потрібно було знати власний шлях. Якщо ви робите щось на зразок отримання pwd, то переконайтеся, що швидко не вдалося / надрукуйте помилку, якщо це не працює, проти просто мовчки, намагаючись продовжити далі.

Див. Також: https://github.com/ipython/ipython/issues/10123


Ви маєте рацію, що неможливо отримати шлях до блокнота за допомогою os.getcwd (). Це просто отримує cwd. Якщо ви змінили це у блокноті, поверніться до цієї комірки, і ви не отримаєте каталог блокнота. ЦЕ ВЕЛИЧЕЗНА ПРОБЛЕМА. І ні, я не згоден з тим, що ви повинні писати свій сценарій таким чином, щоб йому не потрібно було знати, де він знаходиться. Для цього є дуже вагомі причини, наприклад, зробити копію в іншому місці.
зародок
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.