26.Python编程:获取对象信息

# 创建一个猫类对象c
c = Cat()
c.eat()

思考:当我们拿到一个对象的引用时,我们能通过该引用获取该对象的哪些信息呢?例如:创建了一个猫类对象c,我们能根据c,获取到哪些数据信息呢?

再思考:一个对象哪些数据信息是我们开发时所关心的呢?正如你所想到的:对象所属的类型、对象的属性、方法等信息。

本文就来通过对象的引用获取该对象类型、所有的属性和方法。

接下来,我们用Python中自带的函数,来获取以上重要信息。现在我们设计object_info.py模块:包含了Animal类、Cat类、Dog类,代码如下。

# 定义一个动物类Animal
class Animal(object):
    legs = ''  # 腿的数量
    color = ''  # 毛色

    def eat(self):
        print("Animal吃东西")

    def sleep(self):
        print("Animal睡觉")

    def walk(self):
        print("Animal走路")


# 定义一个猫类Cat,继承自动物类Animal
class Cat(Animal):

    def eat(self):
        print("小猫吃鱼")

    def sleep(self):
        print("小猫呼呼睡觉")

    def walk(self):
        print("小猫走猫步")


# 定义一个狗类Dog,继承自动物类Animal
class Dog(Animal):

    def eat(self):
        print("小狗啃骨头")

    def sleep(self):
        print("小狗高度警惕的睡觉")

    def walk(self):
        print("小狗飞奔")

获取类型type(obj)

class type(obj)官方解释:

With one argument, return the type of an object. The return value is a type object and generally the same object as returned by object.__class__.

意思大概是说:type函数传入一个参数时,返回结果是该对象的类型。返回值是type对象,和调用该对象的__class__方法返回值一样。

写出测试代码如下:

# 创建猫类对象c1
c1 = Cat()

# type(obj)
print("type(c1)", type(c1))
print("c1.__class__", c1.__class__)

运行结果:

type(c1): <class '__main__.Cat'>
c1.__class__: <class '__main__.Cat'>

正如官方解释的一样:当type函数传入一个参数时,返回结果是该对象的类型,返回值和调用该对象的__class__方法返回值一样,是一type类型对象。

看到打印结果,这里c1、c2的类型打印结果是:__main__.Cat,为什么多了一部分__main__?前面讲过__main__则是表示我直接运行的当前模块,也就是本例子中object_info.py模块,而不是该模块被其他模块唤起的。

我们再设计另一个模块,my_test.py。文件结构如下:

《26.Python编程:获取对象信息》 文件结构示意图

from object_infos.object_info import Cat

print("--object_info模块被唤起的---")

这次我们运行my_test.py,因为该模块导入了object_info.py模块中的Cat类,所以object_info.py是被动唤起调用的。

运行结果:

type(c1): <class 'object_infos.object_info.Cat'>
c1.__class__: <class 'object_infos.object_info.Cat'>
--object_info模块被唤起的---

看到打印结果,这里c1、c2的类型打印结果不再含有:__main__,而是打印的全类名:object_infos.object_info.Cat。即:object_infos包下的object_info模块中的Cat类。

补充 isinstance(obj, type)

isinstance(obj, type) 函数专门用于判断一个对象是否某个类型。官方解释:

The isinstance() built-in function is recommended for testing the type of an object, because it takes subclasses into account.

意思大概是:当试图判断一个对象是否某个类型时,推荐使用 Python内置的函数isinstance(obj, type),因为该函数会把具有继承关系的类考虑在内。

这怎么理解呢?
object_info.py模块中添加如下代码:

# 创建狗类对象d
d = Dog()
print("isinstance(d, Dog):", isinstance(d, Dog))
print("isinstance(d, Animal):", isinstance(d, Animal))

运行结果:

isinstance(d, Dog): True
isinstance(d, Animal): True

可以看到:狗对象d是狗类实例;狗对象d也是动物类实例,都是True。也就是我们通常所理解的:狗是狗(True),狗是动物(True)。因为Dog类继承自Aniaml类,所以Python内置的函数isinstance(obj, type),会把具有继承关系的类考虑在内。

dir()函数:获取属性和方法

如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法。dir()函数官方解释如下:

Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object.

意思大概是:dir()函数,如果调用时无参调用,则返回当前本地范围中的名称列表。如果调用时传入一个对象参数,则尝试返回该对象的所有的有效属性列表。

也就是传一个对象参数则可返回该对象的所有属性和方法。由于dir()无参时涉及到上下文中,为了更好地看出无参和有餐的dir()函数调用区别,这里把整个模块objcet_info.py贴出来:

# 定义一个动物类Animal
class Animal(object):
    legs = ''  # 腿的数量
    color = ''  # 毛色

    def eat(self):
        print("Animal吃东西")

    def sleep(self):
        print("Animal睡觉")

    def walk(self):
        print("Animal走路")


# 定义一个猫类Cat,继承自动物类Animal
class Cat(Animal):

    def eat(self):
        print("小猫吃鱼")

    def sleep(self):
        print("小猫呼呼睡觉")

    def walk(self):
        print("小猫走猫步")


# 定义一个狗类Dog,继承自动物类Animal
class Dog(Animal):

    def eat(self):
        print("小狗啃骨头")

    def sleep(self):
        print("小狗高度警惕的睡觉")

    def walk(self):
        print("小狗飞奔")


# 创建狗类对象d
d = Dog()
print("isinstance(d, Dog):", isinstance(d, Dog))
print("isinstance(d, Animal):", isinstance(d, Animal))

print("dir()无参调用:", dir())
print("dir(d)传入参数时:", dir(d))

运行结果:

dir()无参调用: ['Animal', 'Cat', 'Dog', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'd']
dir(d)传入参数时: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'color', 'eat', 'legs', 'sleep', 'walk']

使用dir()函数,如果调用时无参调用,则返回当前本地范围中的名称列表,如:’Animal’, ‘Cat’, ‘Dog’,’d’等数据。
如果调用时传入一个对象参数,则尝试返回该对象的所有的有效属性列表。如上运行结果所示。

补充 class type(name, bases, dict)

前面在将type()函数时,官方解释中强调了一个参数的,是因为还有一个同名函数,但需要传入三个参数的,可以动态创建新的class对象,也就是新类型,如:通过该函数动态创建Fox类。 class type(name, bases, dict)的官方解释如下:

With three arguments, return a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the name attribute; the bases tuple itemizes the base classes and becomes the bases attribute; and the dict dictionary is the namespace containing definitions for class body and is copied to a standard dictionary to become the dict attribute. For example, the following two statements create identical type objects。

要创建一个class对象,type()函数依次传入3个参数:
1.新class的名称;
2.所要继承的父类的集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
3.新class中的方法名称与函数可通过字典键值对一一绑定。例如:此参数传入:dict(my_eat=eat)这里我们把函数eat绑定到方法名my_eat上。

通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。

看到这里,你会发现这与Java中的反射机制类似的:运行时动态创建的对象、绑定属性、方法等。接下在学习元类时会专门学习这一块内容。

小结

本文通过对象的引用获取该对象类型、所有的属性和方法。

type()函数传入一个参数时,返回结果是该对象的类型。返回值是type对象,和调用该对象的__class__方法返回值一样。

isinstance(obj, type) 函数专门用于判断一个对象是否某个类型。

dir()函数,如果调用时无参调用,则返回当前本地范围中的名称列表。如果调用时传入一个对象参数,则尝试返回该对象的所有的有效属性列表。

class type(name, bases, dict)可以创建出新的类型。类似Java中的反射机制。

    原文作者:TensorFlow开发者
    原文地址: https://www.jianshu.com/p/15e147f95528
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞