ฉันมีตัวอย่างรหัส 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 Notebook มันจะพิมพ์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) และ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 ไม่โต้ตอบ คุณสามารถโต้แย้งว่ามันควรจะเป็น แต่มันก็ยังคงเป็น gotcha
is_interactive
) ดูเหมือนจะไม่เกี่ยวข้องกับคำถาม นอกจากนี้ยังมีความถูกต้องที่น่าสงสัย ตามที่ @marscher ชี้ให้เห็นว่ามันนับทุกสิ่งที่ทำงานโดยใช้python -c
ในโหมด "โต้ตอบ" แม้ว่าจะไม่เป็นความจริงก็ตาม ฉันไม่อยากทำเองเพราะมันไม่ใช่คำตอบของฉัน แต่ฉันคิดว่าสิ่งนี้จะได้รับการปรับปรุงโดยเพียงแค่ลบคำตอบครึ่งแรกทั้งหมด
เมื่อเร็ว ๆ นี้ฉันพบข้อบกพร่องในสมุดบันทึก Jupyterซึ่งต้องการวิธีแก้ปัญหาชั่วคราวและฉันต้องการทำสิ่งนี้โดยไม่สูญเสียฟังก์ชันการทำงานในเชลล์อื่น ๆ ฉันตระหนักว่าโซลูชันของเคฟลาวิชใช้ไม่ได้ในกรณีนี้เนื่องจากget_ipython()
มีให้บริการโดยตรงจากโน้ตบุ๊กเท่านั้นไม่ใช่จากโมดูลที่นำเข้า ดังนั้นฉันจึงพบวิธีตรวจจับจากโมดูลของฉันว่านำเข้าและใช้งานจากสมุดบันทึก Jupyter หรือไม่:
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
สภาพแวดล้อม Jupyter ของฉัน sys.modules
พจนานุกรมยังไม่รวม'ipykernel'
ที่สำคัญ - เมื่อทำงานภายในโน๊ตบุ๊ค
ทดสอบสำหรับ python 3.7.3
การใช้งาน CPython มีชื่อ__builtins__
เป็นส่วนหนึ่งของ globals ซึ่ง btw สามารถเรียกดูได้โดยฟังก์ชัน 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 โน๊ตบุ๊ค, 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"
สมมติว่าคุณมีการควบคุม Jupyter Notebook คุณสามารถ:
ตั้งค่าสภาพแวดล้อมในเซลล์ที่ใช้นี้เป็นเป็นธงในรหัสของคุณ ใส่ความคิดเห็นที่ไม่ซ้ำกันในเซลล์นั้น (หรือเซลล์ทั้งหมดที่คุณต้องการยกเว้น)
# exclude_from_export
% set_env is_jupyter = 1
ส่งออกสมุดบันทึกเป็นสคริปต์ python เพื่อใช้ในบริบทอื่น การส่งออกจะไม่รวมเซลล์ที่แสดงความคิดเห็นและตามมาด้วยรหัสที่กำหนดค่าสภาพแวดล้อม หมายเหตุ: แทนที่your_notebook.ipynbด้วยชื่อไฟล์สมุดบันทึกจริงของคุณ
jupyter nbconvert - เป็นสคริปต์ --RegexRemovePreprocessor.patterns = "['^ # exclude_from_export']" your_notebook.ipynb
สิ่งนี้จะสร้างไฟล์ที่จะไม่มีการตั้งค่าสถานะสภาพแวดล้อม jupyter เพื่อให้โค้ดที่ใช้มันดำเนินการอย่างกำหนด