跳转至

Python 自省

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

Python dir函数

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

1
2
3
4
5
6
7
>>> 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()函数的输出。

1
2
3
4
5
>>> 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/env python

# direx.py

import sys

class MyObject(object):

   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()返回当前作用域中的名称。

1
2
3
4
5
6
>>> 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/env python

# typefun.py

import sys

def function(): 
    pass

class MyObject(object):

   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/env python

# idfun.py

import sys

def fun(): pass

class MyObject(object):

   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 环境的信息。

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

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

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

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

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

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

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

>>> sys.argv
['']

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

>>> sys.byteorder
'little'

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

其他自省

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

attrs.py
#!/usr/bin/env 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()函数返回属性的内容(如果有的话)。

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

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

1
2
3
4
5
6
>>> 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/env python

# instance.py

class MyObject(object):

   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 中所有对象的基本类型。

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

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

subclass.py
#!/usr/bin/env python

# subclass.py

class Object(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类的子类。 ObjectWall本身也是它们的子类。 Object类不是Wall类的子类。

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

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

namedoc.py
#!/usr/bin/env 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/env python

# callable.py

class Car(object):

    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()方法是可调用的。 (方法是绑定到对象的函数。)

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