阿布云

你所需要的,不仅仅是一个好用的代理。

写Python的新方式

阿布云 发表于

5.png

Org mode is for keeping notes, maintaining TODO lists, planning projects, and authoring documents with a fast and effective plain-text system.

Org-mode 类似于 Markdown , 但是远胜于 Markdown 。 曾有小伙伴说过, Org-mode 是 Markdown 的封神模式, 个人觉得这话一点不夸张, 相比较而言, Markdown 只是一套简洁的文档格式, 而 Org-mode 除了涵盖作为文档格式的简洁之外, 还可用于记笔记,维护 TODO 列表, 工程管理,以及可用于元编程。 对于元编程的支持请阅读我之前的译文, Babel: org-mode的元编程 。

所谓的元编程,即是 Org-mode 搭建了一个多语言可以交互执行的环境, 在这个环境中,可选用各语言的特性,来分解执行一个大型任务。

Org-mode 对于比较流行的语言都有很好的支持, 而且对于新语言,也可以很容易添加支持,本人就给两种语言添加过支持。 本文章主要讲述 Org-mode 对于 Python 源代码块的支持, Python 相当的流行, 所以在 Org-mode 中被很完美的支持。 Org-mode 中的 Python 源代码块可用于定义函数、过滤器和数据分析、创建图表以及生成可重现的研究论文。

配置

这里假设 Python 的开发环境已配置完毕,若是还没配置,请自行google。

Org-mode 已内置在新的 Emacs 中,但是默认情况下, 只有 emacs-lisp 可被执行。 要启用或禁用其他语言, 可通过 Emacs 自定义交互界面来配置 org-babel-load-languages 变量, 或者将代码添加到 init 文件中, 启用python的代码如下所示:

(org-babel-do-load-languages

 'org-babel-load-languages

 '((python . t)))

Org-mode对于Python源码块的支持

头参数

语言特定的头参数

  • :results {output, value}: 默认 value 模式, 即 functional mode , 像函数一样执行,然后返回计算结果。
  • :preamble: 前导代码,插入到最前面(不常用)。 默认为空。
  • :return: 要返回的值(仅用于result-type为 value 时,不在 session 模式下;不常用)。 默认值为空,在 Non-session 模式下,使用 return() 返回值。
  • :python: 执行Python代码的程序名称。

公共头参数

  • :seesion [name]: 默认非 session 模式。
  • :var data=data-table: Org-mode 的 table 可被当做列表传递给Python代码块。
  • :exports {code, results, both, none}: 完全支持 babel 的导出选项。

Sessions

python完全支持 session 模式,包括命名 session 。 在 session 模式下,代码块都运行在同一个长时间运行的 python 的交互式解释器 session 中,就像你在交互式 python 键入的一样。 可以拥有多个 session ,而且它们是完全相互独立。

session 可用于定义函数,设置变量和在源块之间共享代码。

python中的 session 模式与 non-session 模式略有不同,因为在 session 模式下, 你正在与单个“交互式” python session 交互。 在 python 的交互模式中,空行是特殊的:它们表示缩进代码块的结束, 所以会写出一些稍微不同的 python 代码。

另外,在 non-session 模式下,python代码块将被包装在一个函数中, 所以要返回一个值( :result value mode ),你必须使用一个return语句。 在 session 模式下, python 代码由解释器直接评估,而不是在一个函数的上下文中, 最后一个语句的值将被自动返回,因此不能使用 return 语句。

Session mode

# blank lines not OK in indented blocks, and don't use return()

# Source block is passed directly to interactive python;

# value is value of _ at end.

#+begin_src python :session

def foo(x):

  if x>0:

    return x+1

  else:

    return x-1

 

foo(1)

#+end_src

 

#+RESULTS:

: 2

 

Non-session mode

# blank lines OK in indented blocks, and use return()

# Entire source block will get indented and used as the body of main()

#+begin_src python

def foo(x):

  if x>0:

    return x+1

 

  else:

    return x-1

 

return foo(5)

#+end_src

 

#+RESULTS:

: 6

 

最后,如果你使用 matplotlib 的图形功能,同时使用 seesion 模式, 必须显式设置后端, 例如 PDF , PNG 或其他文件导出后端。 见下面示例:

#+begin_src python :session :results file

import matplotlib

matplotlib.use('Agg')

import matplotlib.pyplot as plt

fig=plt.figure(figsize=(3,2))

plt.plot([1,3,2])

fig.tight_layout()

plt.savefig('images/myfig.pdf')

'images/myfig.pdf' # return this to org-mode

#+end_src

 

#+RESULTS:

[[file:images/myfig.pdf]]

返回类型

  • value:=value= 结果是代码块中求值的最后一个表达式的值。 session 模式下使用的python解释器特殊变量“_” 来引用最后一个表达式的值。
  • output:=output= 结果来自 python 代码打印到 stdout 上任意信息。

示例

  • Hello World!

 

#+begin_src python :results output

  print "Hello, world!"

#+end_src

 

#+RESULTS:

: Hello, world!

 

  • 参数

#+NAME: square

#+BEGIN_SRC python :var num=5

  def square(x):

      return x*x

 

  return square(num)

#+END_SRC

 

#+RESULTS: square

: 25

 

#+CALL: square(num=10)

 

#+RESULTS:

: 100

 

  • 文学编程

#+NAME: square

    #+BEGIN_SRC python

      def square(x):

          return x*x

    #+END_SRC

    

    #+NAME: calc-square

    #+BEGIN_SRC python :var num=5 :noweb strip-export :results output

      <<square>>

      print(square(num))

    #+END_SRC

    

    #+RESULTS: calc-square

    : 25

    

    #+CALL: calc-square(num=7)

    

    #+RESULTS:

    : 49

 

  • 内联调用(Inline calling):

    22 等于 src_python{return(2+2)}

    当导出 HTML 或者 LaTeX/PDF 时,如下所示:

    2 加 2 等于 4

  • 使用Org-mode的table作为参数

#+tblname: data_table

| a | 1 |

| b | 2 |

| c | 3 |

#+begin_src python :var val=1 :var data=data_table

# Return row specified by val.

# In non-session mode, use return to return results.

return(data[val])

#+end_src

 

#+RESULTS:

| b | 2 |

 

  • 绘图

#+begin_src python :results file

  import matplotlib, numpy

  matplotlib.use('Agg')

  import matplotlib.pyplot as plt

  fig=plt.figure(figsize=(4,2))

  x=numpy.linspace(-15,15)

  plt.plot(numpy.sin(x)/x)

  fig.tight_layout()

  plt.savefig('../images/python-matplot-fig.png')

  return '../images/python-matplot-fig.png'

#+end_src

 

#+RESULTS:

[[file:../images/python-matplot-fig.png]]

1.png

  • 词云

#+BEGIN_SRC python :preamble "# -*- coding: utf-8 -*-" :results value file

      import jieba.analyse

      from wordcloud import WordCloud, ImageColorGenerator

      import numpy as np

      from PIL import Image

      import random

    

      font_path = '../resource/tyzkaishu.ttf'

      width = 640

      height = 480

    

      text = open('../resource/xiyouji.txt').read()

      words = jieba.analyse.extract_tags(text, topK=200, withWeight=True)

    

      word_freqs = {}

      for word in words:

          word_freqs[word[0]] = word[1]

    

      mask = np.array(Image.open('../resource/stormtrooper_mask.png'))

      wordcloud = WordCloud(

          font_path=font_path, width=width, height=height,

          mask=mask).generate_from_frequencies(word_freqs)

      wordcloud.to_file('../images/xiyouji-mask.png')

      return '../images/xiyouji-mask.png'

    #+END_SRC

    

    #+RESULTS:

    [[file:../images/xiyouji-mask.png]]

2.png

前方预警

当把 utf-8 的字符串传给 Python , 需要格外小心。

传递utf-8字符串到Python

#+NAME: unicode_str

#+BEGIN_EXAMPLE

  “this string is not ascii!”

#+END_EXAMPLE

 

#+NAME: error-in-passing-var

#+BEGIN_SRC python :var data=unicode_str

  return data

#+END_SRC

 

#+RESULTS: error-in-passing-var

 

上面代码不会生成任何输出, 并在 *Org-Babel Error Output* 的缓冲区中打印以下消息:

File “<stdin>”, line 3 SyntaxError: Non-ASCII character ’\xe2’ in file <stdin> on line 3, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

传递utf-8字符串到Python的变通方法

一个变通方法是使用 :preamble ,如下所示:

#+NAME: ok-in-passing-var

#+BEGIN_SRC python :preamble "# -*- coding: utf-8 -*-" :var data=unicode_str

  return data

#+END_SRC

 

#+RESULTS: ok-in-passing-var

: “this string is not ascii!”

 

参考文档