Làm cách nào để kiểm tra xem mã có được thực thi trong sổ ghi chép IPython hay không?


89

Tôi có một số ví dụ về mã Python mà tôi muốn chia sẻ sẽ làm điều gì đó khác biệt nếu được thực thi trong Python / IPython đầu cuối hoặc trong sổ ghi chép IPython.

Làm cách nào tôi có thể kiểm tra từ mã Python của mình nếu nó đang chạy trong sổ ghi chép IPython?


3
Tôi đề nghị chấp nhận câu trả lời của Gustavo Bezerra . Câu trả lời được chấp nhận hiện tại không trả lời câu hỏi và câu trả lời của Gustavo là câu trả lời được điểm cao nhất vẫn hoạt động trong phiên bản mới nhất của Jupyter Notebook.
Mark Amery

Câu trả lời:


9

Câu hỏi là những gì bạn muốn thực hiện khác nhau.

Chúng tôi cố gắng hết sức trong IPython ngăn không cho hạt nhân biết loại giao diện nào được kết nối và thực sự bạn thậm chí có thể có một nhân được kết nối với nhiều giao diện người dùng khác nhau cùng một lúc. Ngay cả khi bạn có thể xem qua kiểu stderr/outđể biết bạn có đang ở trong nhân ZMQ hay không, nó không đảm bảo cho bạn về những gì bạn có ở phía bên kia. Bạn thậm chí có thể không có tiền mặt nào cả.

Bạn có thể nên viết mã của mình theo cách độc lập với giao diện người dùng, nhưng nếu bạn muốn hiển thị những thứ khác nhau, bạn có thể sử dụng hệ thống hiển thị phong phú (liên kết được ghim vào phiên bản 4.x của IPython) để hiển thị những thứ khác nhau tùy thuộc vào giao diện người dùng, nhưng giao diện người dùng sẽ chọn, không phải thư viện.


2
Liên kết ở trên tới Hệ thống hiển thị phong phú IPython bị hỏng. Đây là liên kết đến tài liệu hiện tại: ipython.org/ipython-doc/dev/config/integrating.html và đây là liên kết đến một số ví dụ tuyệt vời: nbviewer.ipython.org/github/ipython/ipython/blob/master/ …
Who8MyLunch

2
Tôi có một vấn đề như thế này trong mô-đun vẽ của tôi . Tôi cần nhập lệnh gọi matplotlib.use ("Agg") ở đó để travis-ci cho phép lưu bản vẽ (xem stackoverflow.com/questions/4706451/… ) Nhưng điều này tạo ra cảnh báo trong sổ ghi chép Người dùng Cảnh báo : Cuộc gọi này tới matplotlib.use () không có hiệu lực vì chương trình phụ trợ đã được chọn; Làm thế nào để giải quyết điều này?
Tiến sĩ Goulu

30
Tôi có một ví dụ: thanh tiến trình. Trình mô phỏng thiết bị đầu cuối máy tính xách tay Jupyter không hỗ trợ các ký tự điều khiển đầu cuối mở rộng như \x1b[A(di chuyển lên), vì vậy không thể in các thanh lồng nhau . Không có vấn đề gì với ipywidgets , chúng ta có thể sử dụng các widget Jupyter gốc để hiển thị các thanh tiến trình. Nhưng sau đó chúng ta có hai phương tiện khác nhau để hiển thị thanh tiến trình và ứng dụng có thể muốn biết môi trường hiển thị là gì để điều chỉnh và in thanh tương thích.
hào nhoáng

2
ví dụ: tôi muốn đặt cấu hình IPython luôn chạy %matplotlib inlinekhi nó hoạt động như một sổ ghi chép, nhưng không phải trong một thiết bị đầu cuối, vì điều đó không cần thiết.
Ciprian Tomoiagă

3
Mặc dù đây là một ý kiến ​​hoàn toàn hợp lệ, nhưng câu trả lời này không giải quyết được câu hỏi thực tế. Bất kể bạn muốn nó như thế nào đi chăng nữa, sẽ luôn có những khác biệt trong hành vi có thể quan trọng.
Christopher Barber

69

Những điều sau đây phù hợp với nhu cầu của tôi:

get_ipython().__class__.__name__

Nó trả về 'TerminalInteractiveShell'trên IPython đầu cuối, 'ZMQInteractiveShell'trên Jupyter (sổ ghi chép VÀ qtconsole) và không thành công ( NameError) trên trình thông dịch Python thông thường. Phương thức này get_python()dường như có sẵn trong vùng tên chung theo mặc định khi IPython được khởi động.

Gói nó trong một chức năng đơn giản:

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

Ở trên đã được thử nghiệm với Python 3.5.2, IPython 5.1.0 và Jupyter 4.2.1 trên macOS 10.12 và Ubuntu 14.04.4 LTS


5
Trên jupyter console, không may get_ipython()trả về một thể hiện của ZMQInteractiveShellcũng
Josh Bode

7
Nếu ai đó đang quan tâm đến việc phát hiện cho dù máy tính xách tay đang chạy trên Google Colab bạn có thể kiểm tra điều này:get_ipython().__class__.__module__ == "google.colab._shell"
guiferviz

3
Điều này chỉ hoạt động đối với mã trong sổ ghi chép. Nó không hoạt động nếu hàm nằm trong một gói đã nhập.
Christopher Barber

4
@ChristopherBarber Đó không phải là những gì tôi thấy. Nếu tôi dán hàm này vào một tệp test.pyrồi chạy from test import isnotebook; print(isnotebook())trong Máy tính xách tay Jupyter, thì hàm này sẽ in True. (Đã thử nghiệm trên máy chủ Notebook phiên bản 5.2.1 và 6.0.1.)
Mark Amery

Tôi nghĩ rằng có một số trường hợp không hiệu quả với tôi, nhưng tiếc là tôi không nhớ chi tiết. Có lẽ nó không còn là một vấn đề hoặc có lẽ tôi chỉ bị nhầm lẫn.
Christopher Barber

41

Để kiểm tra xem bạn có đang ở trong sổ ghi chép hay không, điều này có thể quan trọng, ví dụ như khi xác định loại thanh tiến trình nào sẽ sử dụng, điều này phù hợp với tôi:

def in_ipynb():
    try:
        cfg = get_ipython().config 
        if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
            return True
        else:
            return False
    except NameError:
        return False

6
Trong IPython-Notebook của tôi (IPython phiên bản 3.1), cfg['IPKernelApp']['parent_appname']là một IPython.config.loader.LazyConfigValue, không so sánh Truevới"iypthon-notebook"
Dux

5
@juanjux get_ipython trả về một IPython.kernel.zmq.zmqshell.ZMQInteractiveShellthể hiện trong ipynb (Jupyter) và một IPython.terminal.interactiveshell.TerminalInteractiveShellREPL trong thiết bị đầu cuối, trong trường hợp bạn cần phân biệt giữa sổ ghi chép và thiết bị đầu cuối / bảng điều khiển (điều này ảnh hưởng đến việc vẽ biểu đồ).
hobs

4
^ Do đó bạn có thể thay thế bên trong trykhối với:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
user2561747

Giống như @Dux, điều này không phù hợp với tôi; nó luôn trả về false, ngay cả trong Notebook. Nghi ngờ rằng câu trả lời này đã trở nên lỗi thời với sự ra đời của một số loại hệ thống tải cấu hình lười biếng.
Mark Amery

Cũng lưu ý rằng cấu hình của bạn có thể quay trở lại dưới dạng chính tả trống, trong trường hợp đó, bạn cần thêm KeyError vào khối ngoại trừ. Tuy nhiên, có lẽ tốt hơn là sử dụng mã dựa trên câu trả lời của Gustavo Bezerra. Mặc dù tôi nhận được một cấu hình trống, tôi nhận được shell='PyDevTerminalInteractiveShell'khi kiểm tra tên lớp.
hlongmore

28

Bạn có thể kiểm tra xem python có ở chế độ tương tác hay không bằng đoạn mã sau [1] :

def is_interactive():
    import __main__ as main
    return not hasattr(main, '__file__')

Tôi nhận thấy phương pháp này rất hữu ích vì tôi thực hiện rất nhiều nguyên mẫu trong sổ tay. Đối với mục đích thử nghiệm, tôi sử dụng các tham số mặc định. Nếu không, tôi đọc các thông số từ sys.argv.

from sys import argv

if is_interactive():
    params = [<list of default parameters>]
else:
    params = argv[1:]

Sau khi triển khai autonotebook, bạn có thể biết liệu bạn có đang ở trong sổ ghi chép hay không bằng cách sử dụng mã sau.

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

python -c "def is_interactive ():> import main as main> return not hasattr (main, ' file ')> print is_interactive ()" Đúng
marscher 21/04/2015

3
is_interactive()không phân biệt giữa notebook và console.
krock

1
Một lưu ý khác, việc phát hành %runtừ ipython là không tương tác. Bạn có thể tranh luận rằng nó nên như vậy, nhưng nó vẫn là một gotcha.
dirkjot

Đối với những người khác tạo mẫu trong sổ tay, biến thể của cách tiếp cận của Till được nêu ở đây có thể hữu ích.
Wayne

Nửa sau của câu trả lời này hữu ích, nhưng nửa đầu (về is_interactive) đối với tôi về cơ bản là không liên quan đến câu hỏi. Nó cũng có tính đúng đắn đáng ngờ; như @marscher chỉ ra, nó tính mọi thứ đang chạy bằng cách sử dụng python -cở chế độ "tương tác" mặc dù điều này không đúng. Tôi không muốn tự mình làm điều đó vì đó không phải là câu trả lời của tôi, nhưng tôi nghĩ điều này sẽ được cải thiện bằng cách chỉ cần xóa toàn bộ nửa đầu của câu trả lời.
Mark Amery

17

Gần đây, tôi đã gặp một lỗi trong sổ ghi chép Jupyter cần giải pháp thay thế và tôi muốn thực hiện việc này mà không làm mất chức năng trong các trình bao khác. Tôi nhận ra rằng giải pháp của keflavich không hoạt động trong trường hợp này, vì get_ipython()chỉ có sẵn trực tiếp từ sổ ghi chép chứ không phải từ các mô-đun đã nhập. Vì vậy, tôi đã tìm ra một cách để phát hiện từ mô-đun của mình liệu nó có được nhập và sử dụng từ sổ ghi chép Jupyter hay không:

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

Nhận xét được đánh giá cao nếu điều này là đủ mạnh mẽ.

Theo cách tương tự, có thể lấy một số thông tin về ứng dụng khách và cả phiên bản 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']

Rất tiếc, tôi đang sử dụng Fedora 23 Jupyter và ở đó 'Ipython' in sys.modulesđánh giá False. Có lẽ ý bạn là 'IPython' in sys.modules? Đây là Truetrong môi trường Jupyter của tôi. Các sys.modulestừ điển cũng không bao gồm các 'ipykernel'chìa khóa - khi chạy bên trong một máy tính xách tay.
maxschlepzig,

2
Đây là câu trả lời tốt nhất cho đến nay, IMO. Ngắn và ngọt.
danielpcox

3

Đã thử nghiệm cho python 3.7.3

Triển khai CPython có tên __builtins__có sẵn như một phần của toàn cầu của chúng là btw. có thể được truy xuất bởi hàm Gloals ().
Nếu một tập lệnh đang chạy trong môi trường Ipython thì __IPYTHON__phải là một thuộc tính của __builtins__.
Do đó, mã dưới đây sẽ trả về Truenếu chạy trong Ipython hoặc nếu không, nó sẽ choFalse

hasattr(__builtins__,'__IPYTHON__')

2

Phần sau ghi lại các trường hợp của https://stackoverflow.com/a/50234148/1491619 mà không cần phân tích cú pháp đầu ra củaps

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

Đối với tôi, điều này chỉ hiển thị jupytercho dù đó là một jupyter console, jupyter qtconsolehoặc jupyter notebook.
Luke Davis

2

Tôi khuyên bạn nên tránh phát hiện giao diện người dùng cụ thể vì có quá nhiều trong số chúng . Thay vào đó, bạn chỉ có thể kiểm tra nếu bạn đang chạy từ bên trong môi trường iPython:

def is_running_from_ipython():
    from IPython import get_ipython
    return get_ipython() is not None

Ở trên sẽ trả về Falsenếu bạn đang gọi running_from_ipythontừ dòng lệnh python thông thường. Khi bạn gọi nó từ Jupyter Notebook, JupyterHub, iPython shell, Google Colab, v.v. thì nó sẽ trở lại True.


Không hoạt động với tôi - Khi tôi thử điều này trong Máy tính xách tay Jupyter trên Ubuntu với Python3, get_ipython()trả về <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
nhân vật chính

Vấn đề với cách tiếp cận này là nó không giải quyết được câu hỏi của OP, "Làm thế nào tôi có thể kiểm tra từ mã Python của mình nếu nó đang chạy trong sổ ghi chép IPython ?" (nhấn mạnh của tôi). Vỏ IPython không phải là một sổ ghi chép, nhưng khi tôi chạy nó trong Bảng điều khiển Python của mình trong PyCharm, tôi nhận được kết quả get_ipython() is not Nonetrả về True.
hlongmore

hm, làm thế nào tôi có thể phát hiện ra nếu tôi đang chạy trên jupyter và thì đấy?
ntg

2

Tất cả những gì bạn phải làm là đặt hai ô này ở đầu sổ ghi chép của bạn:

Ô 1: (được đánh dấu là "mã"):

is_notebook = True

Ô 2: (được đánh dấu là "Raw NBConvert"):

is_notebook = False

Ô đầu tiên sẽ luôn được thực thi, nhưng ô thứ hai sẽ chỉ được thực thi khi bạn xuất sổ ghi chép dưới dạng tập lệnh Python.

Sau đó, bạn có thể kiểm tra:

if is_notebook:
    notebook_code()
else:
    script_code()

Hi vọng điêu nay co ich.


2

Còn những thứ như thế này thì sao:

import sys

inJupyter = sys.argv[-1].endswith('json')

print(inJupyter);

1

Theo như tôi biết, Đây có 3 loại ipython được sử dụng ipykernel

  1. ipython qtconsole (viết tắt là "qtipython")
  2. IPython trong spyder (viết tắt là "spyder")
  3. IPython trong sổ ghi chép jupyter (viết tắt là "jn")

sử dụng 'spyder' in sys.modulescó thể phân biệt spyder

nhưng đối với qtipython và jn rất khó phân biệt nguyên nhân

chúng có cùng sys.modulescấu hình IPython:get_ipython().config

Tôi tìm thấy sự khác biệt giữa qtipython và jn:

lần đầu tiên chạy os.getpid()trong IPython shell lấy số pid

sau đó chạy ps -ef|grep [pid number]

pid qtipython của tôi là 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

pid jn của tôi là 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

sự khác biệt của qtipython và jn là tên json của ipython, tên json của jn dài hơn qtipython

vì vậy, chúng tôi có thể tự động phát hiện tất cả Môi trường Python bằng mã sau:

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)

mã nguồn ở đây: Môi trường Python phát hiện, Đặc biệt phân biệt Spyder, sổ ghi chép Jupyter, Qtconsole.py


0

Tôi đang sử dụng Django Shell Plus để khởi chạy IPython và tôi muốn làm cho 'chạy trong máy tính xách tay' khả dụng dưới dạng giá trị cài đặt Django. get_ipython()không khả dụng khi tải cài đặt, vì vậy tôi sử dụng cái này (không chống đạn, nhưng đủ tốt cho môi trường phát triển cục bộ mà nó được sử dụng):

import sys

if '--notebook' in sys.argv:
    ENVIRONMENT = "notebook"
else:
    ENVIRONMENT = "dev"

0

Giả sử bạn có quyền kiểm soát Máy tính xách tay Jupyter, bạn có thể:

  1. đặt một giá trị môi trường trong một ô sử dụng giá trị này làm cờ trong mã của bạn . Đặt một nhận xét duy nhất vào ô đó (hoặc tất cả các ô bạn muốn loại trừ)

    #lude_from_export
    % set_env is_jupyter = 1

  2. Xuất sổ ghi chép dưới dạng tập lệnh python để được sử dụng trong một ngữ cảnh khác. Việc xuất sẽ loại trừ (các) ô được nhận xét và sau đó là mã đặt giá trị môi trường. Lưu ý: thay your_notebook.ipynb bằng tên tệp sổ ghi chép thực của bạn.

    jupyter nbconvert --to script --RegexRemovePreprocessor.patterns = "['^ #lude_from_export']" your_notebook.ipynb

Thao tác này sẽ tạo ra một tệp sẽ không có cờ môi trường jupyter được đặt cho phép mã sử dụng nó để thực thi một cách xác định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.