У мене є приклад коду Python, яким я хотів би поділитися, який повинен робити щось інше, якщо він виконується в терміналі Python / IPython або в блокноті IPython.
Як я можу перевірити з мого коду Python, чи працює він у блокноті IPython?
У мене є приклад коду Python, яким я хотів би поділитися, який повинен робити щось інше, якщо він виконується в терміналі Python / IPython або в блокноті IPython.
Як я можу перевірити з мого коду Python, чи працює він у блокноті IPython?
Відповіді:
Питання в тому, що ви хочете виконати інакше.
Ми робимо все, що в наших силах, у IPython, щоб ядро не знало, до якого типу інтерфейсу підключено, і насправді ви навіть можете одночасно підключити ядро до багатьох різних інтерфейсів. Навіть якщо ви можете підглянути тип, stderr/out
щоб дізнатися, чи перебуваєте ви в ядрі ZMQ, чи ні, це не гарантує вам того, що ви маєте з іншого боку. Ви навіть можете взагалі не мати фронтендів.
Ймовірно, вам слід писати свій код незалежно від інтерфейсу, але якщо ви хочете відображати різні речі, ви можете використовувати розширену систему відображення (посилання, прикріплене до версії 4.x IPython), щоб відображати різні речі залежно від інтерфейсу, але вибере фронтенд, а не бібліотека.
\x1b[A
(переміщення вгору), тому друкувати вкладені смуги неможливо . Немає проблем з ipywidgets , ми можемо використовувати власні віджети Jupyter для відображення індикаторів прогресу. Але тоді ми маємо два різні способи відображення індикатора прогресу, і програма може захотіти знати, що таке середовище відображення, щоб адаптувати та надрукувати сумісну панель.
%matplotlib inline
коли він діє як блокнот, але не в терміналі, оскільки це не потрібно.
Для моїх потреб працювали:
get_ipython().__class__.__name__
Він повертається 'TerminalInteractiveShell'
на терміналі IPython, 'ZMQInteractiveShell'
на Jupyter (ноутбук І qtconsole) і не працює ( NameError
) на звичайному інтерпретаторі Python. get_python()
Здається, метод доступний у глобальному просторі імен за замовчуванням при запуску IPython.
Обертаючи його простою функцією:
def isnotebook():
try:
shell = get_ipython().__class__.__name__
if shell == 'ZMQInteractiveShell':
return True # Jupyter notebook or qtconsole
elif shell == 'TerminalInteractiveShell':
return False # Terminal running IPython
else:
return False # Other type (?)
except NameError:
return False # Probably standard Python interpreter
Вищезазначене було протестовано на Python 3.5.2, IPython 5.1.0 та Jupyter 4.2.1 на macOS 10.12 та Ubuntu 14.04.4 LTS
jupyter console
, на жаль, get_ipython()
повертає екземпляр ZMQInteractiveShell
також
get_ipython().__class__.__module__ == "google.colab._shell"
test.py
а потім запускаю from test import isnotebook; print(isnotebook())
у блокноті Jupyter, вона друкується True
. (Перевірено на сервері Notebook, версії 5.2.1 та 6.0.1.)
Щоб перевірити, чи перебуваєте ви в зошиті, що може бути важливим, наприклад, під час визначення того, який тип індикатора використовувати, це мені вдалося:
def in_ipynb():
try:
cfg = get_ipython().config
if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
return True
else:
return False
except NameError:
return False
cfg['IPKernelApp']['parent_appname']
є a IPython.config.loader.LazyConfigValue
, що не порівняно True
з"iypthon-notebook"
IPython.kernel.zmq.zmqshell.ZMQInteractiveShell
екземпляр у ipynb (Jupyter) та an IPython.terminal.interactiveshell.TerminalInteractiveShell
у терміналі REPL, на випадок, якщо вам потрібно розрізнити блокноти та термінали / консолі (що впливає на побудову графіків).
try
блоку на:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
shell='PyDevTerminalInteractiveShell'
під час перевірки назви класу.
Ви можете перевірити, чи python перебуває в інтерактивному режимі, за допомогою такого фрагмента [1] :
def is_interactive():
import __main__ as main
return not hasattr(main, '__file__')
Я знайшов цей метод дуже корисним, оскільки я роблю багато прототипів у зошиті. Для тестування я використовую параметри за замовчуванням. В іншому випадку я читаю параметри з sys.argv
.
from sys import argv
if is_interactive():
params = [<list of default parameters>]
else:
params = argv[1:]
Після реалізації програми autonotebook
ви можете визначити, чи перебуваєте ви в зошиті, використовуючи наступний код.
def in_notebook():
try:
from IPython import get_ipython
if 'IPKernelApp' not in get_ipython().config: # pragma: no cover
return False
except ImportError:
return False
return True
is_interactive()
не розрізняє блокнот і консоль.
%run
з ipython є неінтерактивним. Можна стверджувати, що так повинно бути, але це все одно проблема.
is_interactive
) мені здається в основному неактуальною для питання. Це також сумнівна коректність; як зазначає @marscher, він вважає, що все, що використовується python -c
, перебуває в "інтерактивному" режимі, хоча це не відповідає дійсності. Я не хочу робити це сам, оскільки це не моя відповідь, але я думаю, що це було б покращено простим видаленням усієї першої половини відповіді.
Нещодавно я зіткнувся з помилкою в ноутбуці Jupyter, яка потребує обхідного шляху , і я хотів зробити це, не втрачаючи функціональності інших оболонок. Я зрозумів, що рішення кефлавича в цьому випадку не працює, оскільки get_ipython()
воно доступне лише безпосередньо з ноутбука, а не з імпортованих модулів. Тож я знайшов спосіб визначити з мого модуля, імпортований він чи використовується із блокнота Юпітера чи ні:
import sys
def in_notebook():
"""
Returns ``True`` if the module is running in IPython kernel,
``False`` if in IPython shell or other Python shell.
"""
return 'ipykernel' in sys.modules
# later I found out this:
def ipython_info():
ip = False
if 'ipykernel' in sys.modules:
ip = 'notebook'
elif 'IPython' in sys.modules:
ip = 'terminal'
return ip
Коментарі вдячні, якщо це досить надійно.
Подібним чином можна отримати деяку інформацію про клієнта, а також версію IPython:
import sys
if 'ipykernel' in sys.modules:
ip = sys.modules['ipykernel']
ip_version = ip.version_info
ip_client = ip.write_connection_file.__module__.split('.')[0]
# and this might be useful too:
ip_version = IPython.utils.sysinfo.get_sys_info()['ipython_version']
'Ipython' in sys.modules
оцінює False
. Можливо, ти маєш на увазі 'IPython' in sys.modules
? Це True
в моєму середовищі Юпітера. sys.modules
Словник також не включає в себе 'ipykernel'
ключ - при роботі всередині ноутбука.
Перевірено на python 3.7.3
Реалізації CPython мають назву, __builtins__
доступну як частина їх глобальних даних, які, до речі. можна отримати за допомогою функції globals ().
Якщо скрипт працює в середовищі Ipython, тоді він __IPYTHON__
повинен бути атрибутом __builtins__
.
Тому наведений нижче код повертається, True
якщо він працює під Ipython або, якщо він надаєтьсяFalse
hasattr(__builtins__,'__IPYTHON__')
Далі описано випадки https://stackoverflow.com/a/50234148/1491619 без необхідності аналізувати результатиps
def pythonshell():
"""Determine python shell
pythonshell() returns
'shell' (started python on command line using "python")
'ipython' (started ipython on command line using "ipython")
'ipython-notebook' (e.g., running in Spyder or started with "ipython qtconsole")
'jupyter-notebook' (running in a Jupyter notebook)
See also https://stackoverflow.com/a/37661854
"""
import os
env = os.environ
shell = 'shell'
program = os.path.basename(env['_'])
if 'jupyter-notebook' in program:
shell = 'jupyter-notebook'
elif 'JPY_PARENT_PID' in env or 'ipython' in program:
shell = 'ipython'
if 'JPY_PARENT_PID' in env:
shell = 'ipython-notebook'
return shell
jupyter
чи є це jupyter console
, jupyter qtconsole
або jupyter notebook
.
Я б рекомендував уникати виявлення конкретного інтерфейсу, оскільки їх занадто багато . Натомість ви можете просто перевірити, чи запускаєте ви всередині середовища iPython:
def is_running_from_ipython():
from IPython import get_ipython
return get_ipython() is not None
Вище повернеться, False
якщо ви звертаєтесь running_from_ipython
із звичайного командного рядка python. Коли ви викликаєте його з Jupyter Notebook, JupyterHub, оболонки iPython, Google Colab тощо, він повернеться True
.
get_ipython()
повертається <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>
.
get_ipython() is not None
повертаюся True
.
Все, що вам потрібно зробити, це розмістити ці дві комірки на початку вашого блокнота:
Осередок 1: (позначений як "код"):
is_notebook = True
Клітинка 2: (позначена як "Raw NBConvert"):
is_notebook = False
Перша комірка завжди буде виконана, але друга комірка буде виконана лише тоді, коли ви експортуєте блокнот як сценарій Python.
Пізніше ви можете перевірити:
if is_notebook:
notebook_code()
else:
script_code()
Сподіваюся, це допомагає.
Як щодо чогось такого:
import sys
inJupyter = sys.argv[-1].endswith('json')
print(inJupyter);
Наскільки я знаю, тут є 3 види ipython, які використовувались ipykernel
ipython qtconsole
(коротше "qtipython")використання 'spyder' in sys.modules
може розрізнити шпигуна
але для qtipython та jn важко розрізнити причину
вони мають однакову sys.modules
та однакову конфігурацію IPython:get_ipython().config
Я знаходжу різницю між qtipython та jn:
перший запуск os.getpid()
в оболонці IPython отримає номер pid
то біжи ps -ef|grep [pid number]
мій qtipython pid - 8699
yanglei 8699 8693 4 20:31 ? 00:00:01 /home/yanglei/miniconda2/envs/py3/bin/python -m ipykernel_launcher -f /run/user/1000/jupyter/kernel-8693.json
мій jn pid - 8832
yanglei 8832 9788 13 20:32 ? 00:00:01 /home/yanglei/miniconda2/bin/python -m ipykernel_launcher -f /run/user/1000/jupyter/kernel-ccb962ec-3cd3-4008-a4b7-805a79576b1b.json
відмінне від qtipython та jn - це ім'я json ipython, ім'я json jn довше, ніж qtipython
отже, ми можемо автоматично виявити все середовище Python за таким кодом:
import sys,os
def jupyterNotebookOrQtConsole():
env = 'Unknow'
cmd = 'ps -ef'
try:
with os.popen(cmd) as stream:
if not py2:
stream = stream._stream
s = stream.read()
pid = os.getpid()
ls = list(filter(lambda l:'jupyter' in l and str(pid) in l.split(' '), s.split('\n')))
if len(ls) == 1:
l = ls[0]
import re
pa = re.compile(r'kernel-([-a-z0-9]*)\.json')
rs = pa.findall(l)
if len(rs):
r = rs[0]
if len(r)<12:
env = 'qtipython'
else :
env = 'jn'
return env
except:
return env
pyv = sys.version_info.major
py3 = (pyv == 3)
py2 = (pyv == 2)
class pyi():
'''
python info
plt : Bool
mean plt avaliable
env :
belong [cmd, cmdipython, qtipython, spyder, jn]
'''
pid = os.getpid()
gui = 'ipykernel' in sys.modules
cmdipython = 'IPython' in sys.modules and not gui
ipython = cmdipython or gui
spyder = 'spyder' in sys.modules
if gui:
env = 'spyder' if spyder else jupyterNotebookOrQtConsole()
else:
env = 'cmdipython' if ipython else 'cmd'
cmd = not ipython
qtipython = env == 'qtipython'
jn = env == 'jn'
plt = gui or 'DISPLAY' in os.environ
print('Python Envronment is %s'%pyi.env)
вихідний код тут: Виявлення середовища Python, Особливо виділяють Spyder, блокнот Jupyter, Qtconsole.py
Я використовую Django Shell Plus для запуску IPython, і я хотів зробити «запуск у блокноті» доступним як значення параметрів Django. get_ipython()
недоступний під час завантаження налаштувань, тому я використовую це (яке не є стійким до кулі, але досить добре для місцевих середовищ розробки, в яких він використовується):
import sys
if '--notebook' in sys.argv:
ENVIRONMENT = "notebook"
else:
ENVIRONMENT = "dev"
Припускаючи, що ви маєте під контролем блокнот Юпітера, ви можете:
встановіть значення середовища в комірці, яка використовує це як прапор у вашому коді . Розмістіть унікальний коментар у цій комірці (або всіх комірках, які ви хочете виключити)
# exclude_from_export
% set_env is_jupyter = 1
Експортуйте блокнот як сценарій python, який буде використовуватися в іншому контексті. Експорт виключає коментовані комірки та згодом код, що встановлює значення середовища. Примітка: замініть your_notebook.ipynb на ім'я вашого фактичного файлу блокнота.
jupyter nbconvert --to script --RegexRemovePreprocessor.patterns = "['^ # exclude_from_export']" your_notebook.ipynb
Це створить файл, у якому не буде встановлено прапор середовища jupyter, що дозволяє коду, який використовує його для детермінованого виконання.