原文: http://zetcode.com/lang/python/introspection/

在 Python 教程的这一部分中,我们讨论了自省。

内省是一种自我检查的行为。 在计算机编程中,自省是在运行时确定对象的类型或属性的能力。 Python 编程语言对自省有很大的支持。 Python 中的所有内容都是一个对象。 Python 中的每个对象都可以具有属性和方法。 通过使用内省,我们可以动态检查 Python 对象。

Python dir函数

dir()函数返回属于对象的属性和方法的排序列表。

  1. >>> dir(())
  2. ['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__',
  3. '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__',
  4. '__getslice__', '__gt__', '__hash__', '__init__', '__iter__', '__le__',
  5. '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__',
  6. '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__',
  7. '__str__', '__subclasshook__', 'count', 'index']

在这里,我们看到了元组对象的dir()函数的输出。

  1. >>> print(().__doc__)
  2. tuple() -> empty tuple
  3. tuple(iterable) -> tuple initialized from iterable's items
  4. If the argument is a tuple, the return value is the same object.

我们的研究表明,元组对象有一个__doc__属性。

direx.py

  1. #!/usr/bin/env python
  2. # direx.py
  3. import sys
  4. class MyObject(object):
  5. def __init__(self):
  6. pass
  7. def examine(self):
  8. print(self)
  9. o = MyObject()
  10. print(dir(o))
  11. print(dir([]))
  12. print(dir({}))
  13. print(dir(1))
  14. print(dir())
  15. print(dir(len))
  16. print(dir(sys))
  17. print(dir("String"))

该示例使用dir()函数检查了几个对象:用户定义的对象,本机数据类型,函数,字符串或数字。

不带任何参数的dir()返回当前作用域中的名称。

  1. >>> dir()
  2. ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
  3. >>> import sys
  4. >>>import math, os
  5. >>> dir()
  6. ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'math', 'sys']

我们在包含一些模块之前和之后执行dir()函数。

Python type()函数

type()函数返回对象的类型。

typefun.py

  1. #!/usr/bin/env python
  2. # typefun.py
  3. import sys
  4. def function():
  5. pass
  6. class MyObject(object):
  7. def __init__(self):
  8. pass
  9. o = MyObject()
  10. print(type(1))
  11. print(type(""))
  12. print(type([]))
  13. print(type({}))
  14. print(type(()))
  15. print(type(object))
  16. print(type(function))
  17. print(type(MyObject))
  18. print(type(o))
  19. print(type(sys))

该示例将各种类型的对象打印到控制台屏幕。

  1. $ ./typefun.py
  2. <class 'int'>
  3. <class 'str'>
  4. <class 'list'>
  5. <class 'dict'>
  6. <class 'tuple'>
  7. <class 'type'>
  8. <class 'function'>
  9. <class 'type'>
  10. <class '__main__.MyObject'>
  11. <class 'module'>

这是输出。

id()函数

id()返回对象的特殊 ID。

idfun.py

  1. #!/usr/bin/env python
  2. # idfun.py
  3. import sys
  4. def fun(): pass
  5. class MyObject(object):
  6. def __init__(self):
  7. pass
  8. o = MyObject()
  9. print(id(1))
  10. print(id(""))
  11. print(id({}))
  12. print(id([]))
  13. print(id(sys))
  14. print(id(fun))
  15. print(id(MyObject))
  16. print(id(o))
  17. print(id(object))

该代码示例打印内置和自定义的各种对象的 ID。

  1. $ ./idfun.py
  2. 10914368
  3. 139696088742576
  4. 139696087935944
  5. 139696065155784
  6. 139696088325640
  7. 139696088244296
  8. 21503992
  9. 139696087910776
  10. 10738720

Python sys模块

sys模块提供对解释器使用或维护的系统特定变量和函数以及与解释器强烈交互的函数的访问。 该模块允许我们查询有关 Python 环境的信息。

  1. >>> import sys
  2. >>> sys.version
  3. '3.5.2 (default, Nov 17 2016, 17:05:23) \n[GCC 5.4.0 20160609]'
  4. >>> sys.platform
  5. 'linux'
  6. >>> sys.path
  7. ['', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu',
  8. '/usr/lib/python3.5/lib-dynload', '/home/janbodnar/.local/lib/python3.5/site-packages',
  9. '/usr/local/lib/python3.5/dist-packages', '/usr/lib/python3/dist-packages']

在上面的代码中,我们检查了 Python 版本,平台和搜索路径位置。

我们还可以使用dir()函数来获取sys模块的变量和函数的完整列表。

  1. >>> sys.executable
  2. '/usr/bin/python3'
  3. >>> sys.argv
  4. ['']
  5. >>> sys.byteorder
  6. 'little'

该示例显示了sys模块的executableargvbyteorder属性。

  1. >>> sys.executable
  2. '/usr/bin/python3'

可执行文件是一个字符串,给出有意义的系统上 Python 解释器的可执行二进制文件的名称。

  1. >>> sys.argv
  2. ['']

这给出了传递给 Python 脚本的命令行参数列表。

  1. >>> sys.byteorder
  2. 'little'

字节顺序是本机字节顺序的指示。 在大端(最高有效字节在前)平台上,值将为"big",在小端(最低有效字节在前)平台值将为"little"

其他自省

接下来,我们展示检查 Python 对象的各种其他方式。

attrs.py

  1. #!/usr/bin/env python
  2. # attr.py
  3. def fun():
  4. pass
  5. print(hasattr(object, '__doc__'))
  6. print(hasattr(fun, '__doc__'))
  7. print(hasattr(fun, '__call__'))
  8. print(getattr(object, '__doc__'))
  9. print(getattr(fun, '__doc__'))

hasattr()函数检查对象是否具有属性。 getattr()函数返回属性的内容(如果有的话)。

  1. $ ./attr.py
  2. True
  3. True
  4. True
  5. The most base type
  6. None

isinstance函数检查对象是否为特定类的实例。

  1. >>> print(isinstance.__doc__)
  2. Return whether an object is an instance of a class or of a subclass thereof.
  3. A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the target to
  4. check against. This is equivalent to ``isinstance(x, A) or isinstance(x, B)
  5. or ...`` etc.

我们可以交互地描述一个函数。

instance.py

  1. #!/usr/bin/env python
  2. # instance.py
  3. class MyObject(object):
  4. def __init__(self):
  5. pass
  6. o = MyObject()
  7. print(isinstance(o, MyObject))
  8. print(isinstance(o, object))
  9. print(isinstance(2, int))
  10. print(isinstance('str', str))

众所周知,一切都是 Python 中的对象; 偶数和字符串。 object是 Python 中所有对象的基本类型。

  1. $ ./instance.py
  2. True
  3. True
  4. True
  5. True

issubclass()函数检查特定的类是否是另一个类的派生类。

subclass.py

  1. #!/usr/bin/env python
  2. # subclass.py
  3. class Object(object):
  4. def __init__(self):
  5. pass
  6. class Wall(Object):
  7. def __init__(self):
  8. pass
  9. print(issubclass(Object, Object))
  10. print(issubclass(Object, Wall))
  11. print(issubclass(Wall, Object))
  12. print(issubclass(Wall, Wall))

在我们的代码示例中,Wall类是Object类的子类。 ObjectWall本身也是它们的子类。 Object类不是Wall类的子类。

  1. $ ./subclass.py
  2. True
  3. False
  4. True
  5. True

__doc__属性提供了有关对象的一些文档,__name__属性包含对象的名称。

namedoc.py

  1. #!/usr/bin/env python
  2. # namedoc.py
  3. def noaction():
  4. '''A function, which does nothing'''
  5. pass
  6. funcs = [noaction, len, str]
  7. for i in funcs:
  8. print(i.__name__)
  9. print(i.__doc__)
  10. print("-" * 75)

在我们的示例中,我们创建了三个函数的列表:一个自定义函数和两个本机函数。 我们浏览列表并打印__name____doc__属性。

  1. $ ./namedoc.py
  2. noaction
  3. A function, which does nothing
  4. ---------------------------------------------------------------------------
  5. len
  6. Return the number of items in a container.
  7. ---------------------------------------------------------------------------
  8. str
  9. str(object='') -> str
  10. str(bytes_or_buffer[, encoding[, errors]]) -> str
  11. Create a new string object from the given object. If encoding or
  12. errors is specified, then the object must expose a data buffer
  13. that will be decoded using the given encoding and error handler.
  14. Otherwise, returns the result of object.__str__() (if defined)
  15. or repr(object).
  16. encoding defaults to sys.getdefaultencoding().
  17. errors defaults to 'strict'.
  18. ---------------------------------------------------------------------------

这是输出。

最后,还有一个callable()函数。 该函数检查对象是否为可调用对象(函数)。

callable.py

  1. #!/usr/bin/env python
  2. # callable.py
  3. class Car(object):
  4. def setName(self, name):
  5. self.name = name
  6. def fun():
  7. pass
  8. c = Car()
  9. print(callable(fun))
  10. print(callable(c.setName))
  11. print(callable([]))
  12. print(callable(1))

在代码示例中,我们检查三个对象是否可调用。

  1. print(callable(fun))
  2. print(callable(c.setName))

fun()函数和setName()方法是可调用的。 (方法是绑定到对象的函数。)

  1. $ ./callable.py
  2. True
  3. True
  4. False
  5. False

在 Python 教程的这一部分中,我们讨论了 Python 中的自省。 在inspect模块中可以找到更多进行内省的工具。