# 创建一个猫类对象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
。文件结构如下:
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中的反射机制。