У мене є приклад коду 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, що дозволяє коду, який використовує його для детермінованого виконання.