ZetCode

Python 内省

最后修改于 2024 年 1 月 29 日

在本文中,我们将讨论 Python 中的内省。

内省是一种自我检查的行为。在计算机编程中,内省是指在运行时确定对象类型或属性的能力。Python 编程语言对内省提供了广泛的支持。Python 中的一切都是对象。Python 中的每个对象都可以拥有属性和方法。通过使用内省,我们可以动态地检查 Python 对象。

Python dir 函数

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

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

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

>>> print(().__doc__)
tuple() -> empty tuple
tuple(iterable) -> tuple initialized from iterable's items

If the argument is a tuple, the return value is the same object.

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

direx.py
#!/usr/bin/python

# direx.py

import sys

class MyObject:

   def __init__(self):
      pass

   def examine(self):
      print(self)


o = MyObject()

print(dir(o))
print(dir([]))
print(dir({}))
print(dir(1))
print(dir())
print(dir(len))
print(dir(sys))
print(dir("String"))

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

不带任何参数时,`dir` 返回当前作用域中的名称。

>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
>>> import sys
>>>import math, os
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'math', 'sys']

我们在导入一些模块之前和之后执行了 `dir` 函数。

Python type 函数

type 函数返回对象的类型。

typefun.py
#!/usr/bin/python

# typefun.py

import sys

def function():
    pass

class MyObject:

   def __init__(self):
      pass

o = MyObject()

print(type(1))
print(type(""))
print(type([]))
print(type({}))
print(type(()))
print(type(object))
print(type(function))
print(type(MyObject))
print(type(o))
print(type(sys))

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

$ ./typefun.py
<class 'int'>
<class 'str'>
<class 'list'>
<class 'dict'>
<class 'tuple'>
<class 'type'>
<class 'function'>
<class 'type'>
<class '__main__.MyObject'>
<class 'module'>

id 函数

id 返回对象的特殊 ID。

idfun.py
#!/usr/bin/python

# idfun.py

import sys

def fun(): pass

class MyObject:

   def __init__(self):
      pass

o = MyObject()

print(id(1))
print(id(""))
print(id({}))
print(id([]))
print(id(sys))
print(id(fun))
print(id(MyObject))
print(id(o))
print(id(object))

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

$ ./idfun.py
10914368
139696088742576
139696087935944
139696065155784
139696088325640
139696088244296
21503992
139696087910776
10738720

Python sys 模块

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

>>> import sys >>> sys.version '3.11.1 (tags/v3.11.1:a7a450f,
Dec  6 2022, 19:58:39) [MSC v.1934 64 bit (AMD64)]' >>> sys.platform
'win32' >>> sys.path ['',
'C:\\Users\\Jano\\AppData\\Local\\Programs\\Python\\Python311\\python311.zip',
'C:\\Users\\Jano\\AppData\\Local\\Programs\\Python\\Python311\\Lib',
'C:\\Users\\Jano\\AppData\\Local\\Programs\\Python\\Python311\\DLLs',
'C:\\Users\\Jano\\AppData\\Local\\Programs\\Python\\Python311',
... ']

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

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

>>> sys.executable
'C:\\Users\\Jano\\AppData\\Local\\Programs\\Python\\Python311\\python.exe'
>>> sys.argv
['']
>>> sys.byteorder
'little'

该示例展示了 `sys` 模块的 `executable`、`argv` 和 `byteorder` 属性。

>>> sys.executable
'C:\\Users\\Jano\\AppData\\Local\\Programs\\Python\\Python311\\python.exe'

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

>>> sys.argv
['']

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

>>> sys.byteorder
'little'

byteorder 是本机字节顺序的指示符。在大端(最高有效字节在前)平台上,它将具有值“big”,在小端(最低有效字节在前)平台上,它将具有值“little”。

其他内省

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

attrs.py
#!/usr/bin/python

# attr.py

def fun():
    pass

print(hasattr(object, '__doc__'))
print(hasattr(fun, '__doc__'))
print(hasattr(fun, '__call__'))

print(getattr(object, '__doc__'))
print(getattr(fun, '__doc__'))

hasattr 函数检查对象是否具有某个属性。`getattr` 函数在存在某些属性时返回该属性的内容。

$ ./attr.py
True
True
True
The most base type
None

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

>>> print(isinstance.__doc__)
Return whether an object is an instance of a class or of a subclass thereof.

A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the target to
check against. This is equivalent to ``isinstance(x, A) or isinstance(x, B)
or ...`` etc.

我们可以交互式地获取函数的描述。

instance.py
#!/usr/bin/python

# instance.py

class MyObject:

   def __init__(self):
      pass

o = MyObject()

print(isinstance(o, MyObject))
print(isinstance(o, object))
print(isinstance(2, int))
print(isinstance('str', str))

正如我们所知,Python 中的一切都是对象;甚至是数字和字符串。`object` 是 Python 中所有对象的基类。

$ ./instance.py
True
True
True
True

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

subclass.py
#!/usr/bin/python

# subclass.py

class Object:

   def __init__(self):
      pass

class Wall(Object):

   def __init__(self):
      pass

print(issubclass(Object, Object))
print(issubclass(Object, Wall))
print(issubclass(Wall, Object))
print(issubclass(Wall, Wall))

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

$ ./subclass.py
True
False
True
True

`__doc__` 属性提供有关对象的文档,而 `__name__` 属性保存对象的名称。

namedoc.py
#!/usr/bin/python

# namedoc.py

def noaction():
   '''A function, which does nothing'''
   pass

funcs = [noaction, len, str]

for i in funcs:

   print(i.__name__)
   print(i.__doc__)
   print("-" * 75)

在我们的示例中,我们创建了一个包含三个函数的列表:一个自定义函数和两个内置函数。我们遍历列表并打印 `__name__` 和 `__doc__` 属性。

$ ./namedoc.py
noaction
A function, which does nothing
---------------------------------------------------------------------------
len
Return the number of items in a container.
---------------------------------------------------------------------------
str
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.
---------------------------------------------------------------------------

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

callable.py
#!/usr/bin/python

# callable.py

class Car:

    def setName(self, name):
        self.name = name

def fun():
    pass

c = Car()

print(callable(fun))
print(callable(c.setName))
print(callable([]))
print(callable(1))

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

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

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

$ ./callable.py
True
True
False
False

来源

Python inspect 模块

在本文中,我们讨论了 Python 中的内省。更多用于执行内省的工具可以在 `inspect` 模块中找到。

作者

我叫 Jan Bodnar,是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Python 教程