文章目录

  • help() 函数
  • help()详解
  • help不是一个函数
  • help的导入过程
  • object.\_\_call__(self [, args ...]) 函数
  • site.py模块 与 -S 选项


help() 函数

通常当我们执行python命令进入交互式命令行界面后,可以使用help()来打印某个对象的帮助信息。例如,

>>> help(open)
Help on built-in function open in module io:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
    Open file and return a stream.  Raise OSError upon failure.
   ... (后续输出省略)

help()详解

help不是一个函数

当我们在Python命令行提示符>>>下:

  1. 检查help的类型时,会发现help其实指向一个类的实例,类名是_sitebuiltins._Helper。
  2. 打印help对象本身的信息时,会发现打印出了一个字符串
    Type help() for interactive help, or help(object) for help about object.
    而不是像其他内置函数一样打印出
    <built-in function xxx>。
>>> type(help)
<class '_sitebuiltins._Helper'>

>>> help
Type help() for interactive help, or help(object) for help about object.

>>> open
<built-in function open>

help的导入过程

当执行python命令时,如果没有使用-S 选项(表示不导入site库),python会隐式导入’/usr/local/lib/python3.7/site.py’(目录随Python安装目录和版本变化)文件,site.py导入_sitebuiltins模块后,设置help对象指向 _sitebultins._Helper类的实例(当然也类似地设置了其他的一些对象和函数)。
具体过程参考如下:

# from site.py
# import another module
import _sitebuiltins

# 将_Helper类的实例设置给builtins模块的help对象。
# 任何时候都可以在命令行提示符使用help对象
def setHelper():
	builtins.help = _sitebuiltins._Helper()

# main()函数执行setHelper()函数以及其他设置函数
def main():
	...
	setHelper()
	...

# if NO (-S) option, 
# will execute main() function
if not sys.flags.no_site:
	main()

下面具体看一下_sitebuiltins.py模块中_Helper类的定义,一切都会非常明晰。 这个类定义了__call__函数,使得这个对象变成了可调用对象(callable object),也就支持了help(object)这种格式,help用起来就像是一个函数了。在__call__的定义中,最终使用了pydoc.help()函数来生成对象的帮助信息。

# from _sitebuiltins.py
class _Helper(object):
	""" doc string omitted """
	
	# >>>help 
	# will print out the string below
	def __repr__(self):
		return "Type help() for interactive help, " \
			"or help(object) for help about objects."

	def __call__(self, *args, **kwds)
		import pydoc
		return pydoc.help(*args, **kwds)

object.__call__(self [, args …]) 函数

在定义类的时候,可以定义一个特殊的__call__函数,这样类的实例就可以像函数一个被 “调用” 了。
例如:

>>> class foo:
...     def __call__(self, msg):
...             print(msg) 
...             return msg
... 
>>> 
>>> myfoo = foo()
>>> m = myfoo("Hello Callable Object")
Hello Callable Object
>>> print(m)
Hello Callable Object

有了可调用对象后,如果不使用type(object)来查看对象的实际类型,一般情况很难确定对象是一个函数还是还是一个类实例,因为调用的语法格式都一样。但是初学者,尤其是强类型语言背景的,很容易在这里迷惑。

# help 指向一个类实例
>>> type(help)
<class '_sitebuiltins._Helper'>

# help对象的字符串表示
>>> help
Type help() for interactive help, or help(object) for help about object.

# 等价于执行 help.__call__(help)
>>> help(help)

site.py模块 与 -S 选项

上文中提到 -S 选项表示Python启动时不要加载 site模块。
https://docs.python.org/3/library/site.html site模块会把site-packages目录添加到模块搜索路径中,并且添加一些内置函数,例如quit(),help()等。

# 使用-S选项
[stack@tony-devstack nova]$ python3 -S
Python 3.7.5 (default, Nov 14 2019, 12:57:28) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux

# 检查模块搜素路径
>>> import sys
>>> sys.path
['', 
'/usr/local/lib/python37.zip', 
'/usr/local/lib/python3.7', 
'/usr/local/lib/python3.7/lib-dynload']

# 可以导入标准库模块
>>> import io
>>> io
<module 'io' from '/usr/local/lib/python3.7/io.py'>

# 无法导入site-packages目录下的模块
>>> import flake8
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'flake8'

# quit()/exit()/help()函数皆不可用
>>> quit()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'quit' is not defined
>>> exit()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'exit' is not defined
>>> help()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'help' is not defined
# 不使用 -S 选项
[stack@tony-devstack site-packages]$ python3 
Python 3.7.5 (default, Nov 14 2019, 12:57:28) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.

# 注意模块搜索路径中包括了site-packages目录
>>> import sys
>>> sys.path
['', 
 '/usr/local/lib/python37.zip', 
 '/usr/local/lib/python3.7', 
 '/usr/local/lib/python3.7/lib-dynload', 
 '/usr/local/lib/python3.7/site-packages']

# 成功导入了site-packages/目录下的flake模块
>>> import flake8
>>> flake8
<module 'flake8' from '/usr/local/lib/python3.7/site-packages/flake8/__init__.py'>

# exit()/quit()/help()都存在
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
>>> quit
Use quit() or Ctrl-D (i.e. EOF) to exit
>>> help
Type help() for interactive help, or help(object) for help about object.

# exit和quit都是 _sitebuiltins.Quitter类的实例
>>> type(exit)
<class '_sitebuiltins.Quitter'>
>>> type(quit)
<class '_sitebuiltins.Quitter'>

# help也是一个类实例
>>> type(help)
<class '_sitebuiltins._Helper'>

# exit与quit并不指向同一个实例,尽管作用相同。
>>> exit is quit
False

# 打印出的字符床略有不同。
>>> quit                   
Use quit() or Ctrl-D (i.e. EOF) to exit
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit