python自省与反射

DAY 5. python自省

这是很久之前写的,当时对自省和反射的概念没理解,学习Java以后多了一点理解,自省是获取对象的能力,反射是操纵对象的能力,python中使用getattr()setattr()实现反射,而其他的则是自省,下面的内容是把两者混在一起说的,但又不想改了,内容罗里吧嗦,把最终的总结提到前面

方法 作用
help() 查看函数或模块用途的详细说明
dir() 返回对象所有属性
type() 查看对象类型
hasattr() 查看对象是否有特定属性
getattr() 得到对象的特定属性
setattr() 设置对象的特定属性
isinstance() 判断一个对象是否是一个已知的类型
issubclass() 判断一个类是不是另一个类的子类
id() 返回地址值
callable() 判断对象是否可调用

In computing, type introspection is the ability of a program to examine the type or properties of an object at runtime. Some programming languages possess this capability.
在计算机科学中,内省是指计算机程序在运行时(Run time)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查

这是维基百科对自省(内省)的解释,通俗来说,自省就是在程序运行过程中,能够知道对象的类型的一种能力,大部分语言都有这种能力(都有办法在运行过程中知道对象的类型),如c++,Java等

当然自省不仅仅只针对对象的类型,如python自省还能知道对象的属性,还有一些其他的理解

在日常生活中,自省(introspection)是一种自我检查行为。

在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。

说的更简单直白一点:自省就是面向对象的语言所写的程序在运行时,能够知道对象的类型。简单一句就是,运行时能够获知对象的类型。

例如c++自省(来自维基百科)

C ++通过运行时类型信息(RTTI)typeid和dynamic_cast关键字支持类型内省。 dynamic_cast表达式可用于确定特定对象是否属于特定派生类。 例如:

Person* p = dynamic_cast<Person *>(obj);
if (p != nullptr) {
  p->walk();
}

typeid运算符检索std :: type_info对象,该对象描述对象的派生类型:

if (typeid(Person) == typeid(*obj)) {
  serialize_person( obj );
}

php自省(来自维基百科)

在php中,可以使用instanceof运算符判断一个PHP变量是否属于某一类的实例

if ($obj instanceof Person) {
    // Do whatever you want
}

Java自省(来自维基百科)

Java中类型自省的最简单示例是instanceof运算符。 instanceof运算符确定特定对象是属于特定类(或该类的子类,还是实现该接口的类)。 例如:

if (obj instanceof Person) {
    Person p = (Person)obj;
    p.walk();
}

5.1 python实现自省的办法

python实现自省有很多方法,常用的有 help(),dir(),type(),hasattr(),getattr(),setattr(),isinstance(),issubclass(),id(),callable()

5.1.1 help()

help() 函数用于查看函数或模块用途的详细说明。主要在IDE环境下是用,接受任何拥有函数或者方法的对象,打印出对象所有的函数和文档字符串

如可以直接打印出os模块的帮助文档

import os
help(os)
# Help on module os:
#
# NAME
#     os - OS routines for NT or Posix depending on what system we're on.
#
# DESCRIPTION
# 后面的省略了

也可以是我们自定义的类,函数,或模块

class Demo:
    """
    this is a Demo
    """
    classVar = 0

    def __init__(self):
        self.var1 = 1

    def output(self):
        print(self.var1)

if __name__ == '__main__':
    help(Demo)

运行之后会打印出这个类的完整信息

Help on class Demo in module __main__:

class Demo(builtins.object)
 |  this is a Demo
 |  
 |  Methods defined here:
 |  
 |  __init__(self)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  output(self)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  classVar = 0

实例对象会打印出类的信息

函数会打印出帮助文档,没有文档会打印none

 def demoMethods(a):
        """
        这是一个示例函数
        :param a: 示例形参
        :return: None
        """
        print(a)
    help(demoMethods)
# Help on function demoMethods in module __main__:

# demoMethods(a)
#     这是一个示例函数
#     :param a: 示例形参
#     :return: None

更详细的请看这篇文章

Python-自省机制

5.1.2 dir()

dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。

dir()
['__builtins__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'sys']
dir([])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

5.1.3 hasattr(),getattr(),setattr()

class Demo:
    def __init__(self):
        self.var1 = 0
        self.var2 = 1

if __name__ == '__main__':
    demo = Demo()
    if hasattr(demo,'var1'):
        setattr(demo,'var1',2)
    print(getattr(demo,'var1','not find'))  # 2
    print(getattr(demo,'var11','not find'))  # not find
  • hasattr()
def hasattr(*args, **kwargs): # real signature unknown
    """
    Return whether the object has an attribute with the given name.
    返回对象是否具有给定名称的属性。

    This is done by calling getattr(obj, name) and catching AttributeError.
    这是通过调用getattr(obj,name)并捕获AttributeError来完成的.
    """
    pass
  • setattr()
def setattr(x, y, v): # real signature unknown; restored from __doc__
    """
    Sets the named attribute on the given object to the specified value.
    将给定对象的命名属性设置为指定值。

    setattr(x, 'y', v) is equivalent to ``x.y = v''
    setattr(x,‘y’,v)等价于“x.y=v”
    """
    pass
  • getattr()
def getattr(object, name, default=None): # known special case of getattr
    """
    getattr(object, name[, default]) -> value

    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
    从对象中获取指定名称的属性;getattr(x,‘y’)等同于X.Y。
    如果给定了默认参数,则未找到该属性时将返回该参数。
    如果未指定,则会引发异常。
    """
    pass

5.1.4 isinstance(),issubclass()

>>> help(isinstance)
Help on built-in function isinstance in module builtins:

isinstance(obj, class_or_tuple, /)
    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类似于type(),只不过type() 不会认为子类是一种父类类型,不考虑继承关系。isinstance() 会认为子类是一种父类类型,考虑继承关系。

>>> class A:
	pass

>>> a = A()
>>> isinstance(a,type)
False
>>> class B(A):
	pass

>>> b=B()
>>> isinstance(b,A)
True
>>> isinstance(int,type)
True
>>> isinstance(A,type)
True
>>> isinstance(b,type)
False
>>> isinstance(True,int)
True

可以看出类是type的子类型,也验证了前天的元类,而布尔是int的子类

而issubclass()则是用来判断一个类是不是另一个类的子类,传入的两个参数都是类名

>>> issubclass(B,A)
True

5.1.5 id()和callable()

  • id(): 用于获取对象的内存地址
  • callable():判断对象是否可以被调用。

5.1.6 type()

这个函数在元类中写过了,当传入一个参数时会返回对象的类型,这也是python自省中比较常用的方法

5.2 总结

  • 什么是自省

简单来说就是在程序运行过程中能知道对象类型(还有属性等)的能力

  • python实现自省的方法
方法 作用
help() 查看函数或模块用途的详细说明
dir() 返回对象所有属性
type() 查看对象类型
hasattr() 查看对象是否有特定属性
getattr() 得到对象的特定属性
seetattr() 设置对象的特定属性
isinstance() 判断一个对象是否是一个已知的类型
issubclass() 判断一个类是不是另一个类的子类
id() 返回地址值
callable() 判断对象是否可调用

参考文章

python面试题

wikipedia Type introspection

Python自省(反射)指南【转】

在这篇文章中说

在笔者,也就是我的概念里,自省和反射是一回事,当然其实我并不十分确定一定以及肯定…

但是我在维基百科看见了这句话

Introspection should not be confused with reflection, which goes a step further and is the ability for a program to manipulate the values, meta-data, properties and/or functions of an object at runtime.

也就是说自省和反射不是同一回事,自省是获取对象类型的能力,而反射是操纵对象的值,元数据,属性和/或函数的能力

Python常用的自省函数

Python-自省机制

Python自省

菜鸟教程

发布了62 篇原创文章 · 获赞 33 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/zjbyough/article/details/96037399