本章我们讨论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/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()返回当前作用域中的名称。
>>> 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 环境的信息。
>>> 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模块的变量和函数的完整列表。
>>> sys.executable '/usr/bin/python3' >>> sys.argv [''] >>> sys.byteorder 'little'
该示例显示了sys模块的executable,argv和byteorder属性。
>>> 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()函数返回属性的内容(如果有的话)。
$ ./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/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 中所有对象的基本类型。
$ ./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类的子类。 Object和Wall本身也是它们的子类。 Object类不是Wall类的子类。
$ ./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()方法是可调用的。 (方法是绑定到对象的函数。)
$ ./callable.py True True False False