获取对象信息
拿到一个变量, 除了用 isinstance() 判断它是否是某种类型的实例外, 还有没有别的方法获取到更多的信息呢?
例如, 已有定义:
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
def whoAmI(self):
return 'I am a Student, my name is %s' % self.name
首先可以用 type() 函数获取变量的类型, 它返回一个 Type 对象:
>>> type(123)
<type 'int'>
>>> s = Student('Bob', 'Male', 88)
>>> type(s)
<class '__main__.Student'>
其次, 可以用 dir() 函数获取变量的所有属性:
>>> dir(123) # 整数也有很多属性...
['__abs__', '__add__', '__and__', '__class__', '__cmp__', ...]
>>> dir(s)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'gender', 'name', 'score', 'whoAmI']
对于实例变量, dir() 返回所有实例属性, 包括__class__这类有特殊意义的属性. 注意到方法 whoAmI 也是 s 的一个属性.
如何去掉__xxx__这类的特殊属性, 只保留我们自己定义的属性? 回顾一下 filter() 函数的用法.
dir() 返回的属性是字符串列表, 如果已知一个属性名称, 要获取或者设置对象的属性, 就需要用 getattr() 和 setattr( ) 函数了:
>>> getattr(s, 'name') # 获取 name 属性
'Bob'
>>> setattr(s, 'name', 'Adam') # 设置新的 name 属性
>>> s.name
'Adam'
>>> getattr(s, 'age') # 获取 age 属性, 但是属性不存在, 报错:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'age'
>>> getattr(s, 'age', 20) # 获取 age 属性, 如果属性不存在, 就返回默认值 20:
20
新式类和旧式类
python 的新式类是 2.2 版本引进来的, 我们可以将之前的类叫做经典类或者旧类.
为什么要在 2.2 中引进 new style class 呢? 官方给的解释是: 为了统一类 (class) 和类型 (type).
在 2.2 之前, 比如 2.1 版本中, 类和类型是不同的,
如 a 是 ClassA 的一个实例,
那么 a.__class__返回
class __main__.ClassA
,type(a) 返回总是
<type 'instance'>
.
而引入新类后, 比如 ClassB 是个新类, b 是 ClassB 的实例, b.__class__和 type(b) 都是返回
'class'__main__.ClassB'
, 这样就统一了.
引入新类后, 还有其他的好处, 比如更多的内置属性将会引入, 描述符的引入, 属性可以来计算等等. 为了向前兼容, 默认情况下用户定义的类为经典类, 新类需要继承自所有类的基类 object 或者继承自 object 的新类.
值得注意的地方是, 虽然使用的是最新的 python(2.7), 但是一些特性不会在旧式类起作用.
所以, 为了确保自己使用的是新式类, 有以下方法:
把这个赋值语句放在类模块代码的最前面
__metaclass__ = type
(前面有提过).
自己的类都从内建类 object 直接或者间接地继承.
如果不需要兼容旧式类, 旧版本的类, 那么就保持都是新式类.
当然, 在 Python3 里面, 不存在这些问题了, 因为所有的类都是 object 类的子类(隐式).
# encoding:utf-8
# 新式类和旧式类的对比
class OldStyle:
def __init__(self, name, description):
self.name = name
self.description = description
# 新类, 可以在这里加 __metaclass__ = type
class NewStyle(object): #新类, 也可以直接继承至 object 类
def __init__(self, name, description):
self.name = name
self.description = description
if __name__ == '__main__':
old = OldStyle('old', 'Old style class')
print(old.__class__)
print((type(old)))
print((dir(old)))
print('-------------------------------------------------------')
new = NewStyle('new', 'New style class')
print(new.__class__)
print((type(new)))
print((dir(new)))
运行结果:
__main__.OldStyle
<type 'instance'>
['__doc__', '__init__', '__module__', 'description', 'name']
-------------------------------------------------------
<class '__main__.NewStyle'>
<class '__main__.NewStyle'>
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'description', 'name']
[Finished in 0.1s]
多继承属性查找机制
如果将每个类看成一个点, 众多的类就构成一张图, 那么 Python 中继承的机制是就是一种搜索
那么地, 这种搜索是深度优先搜索, 还是广度优先搜索呢?
上述的问题也叫做 mro 即
method resolution order
, 主要用于在多继承时判断调的属性的路径 (来自于哪个类).
在旧式类 (在 Python2.3 之前) 之中类的多继承机制是基于深度优先搜索, 但在新式类 (从 Python2.3 起) 之中类的多继承机制是基于类似于广度优先搜索的 C3 算法.
C3 算法
C3 算法最早被提出是用于 Lisp 的, 应用在 Python 中是为了解决原来基于深度优先搜索算法不满足本地优先级, 和单调性的问题.
本地优先级: 指声明时父类的顺序, 比如 C(A,B), 如果访问 C 类对象属性时, 应该根据声明顺序, 优先查找 A 类, 然后再查找 B 类.
单调性: 如果在 C 的解析顺序中, A 排在 B 的前面, 那么在 C 的所有子类里, 也必须满足这个顺序.
在新式类中, 查找一个要调用的函数或者属性的时候, 是广度优先搜索的.
在旧式类当中, 是深度优先搜索的. 如下图所示:
Python 中几种提供继承顺序的方法:
mro 方法
__mro__属性
inspect 模块的 getmro 方法
import inspect
class A:
pass
class B(A):
pass
print(B.mro())
print(B.__mro__)
print(inspect.getmro(B))
运行结果:
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
从上结果来看, 以元组为结果的__mro__和 inspect.getmro 看来更让人满意
深度优先和广度优先
旧式类的深度优先搜索的继承机制
# -*- coding:utf-8 -*-
from inspect import getmro
class D:
pass
class B(D):
pass
class C(D):
pass
class A(B, C):
pass
if __name__ == '__main__':
print(getmro(A))
运行结果:
(<class __main__.A at 0x0000000002CEC888>, <class __main__.B at 0x0000000002CECE88>,
<class __main__.D at 0x0000000002CEC8E8>, <class __main__.C at 0x0000000002CECD68>)
[Finished in 0.1s]
新式类的广度优先搜索的继承机制
# -*- coding:utf-8 -*-
from inspect import getmro
class D(object):
pass
class B(D):
pass
class C(D):
pass
class A(B, C):
pass
if __name__ == '__main__':
print(getmro(A))
运行结果:
(<class '__main__.A'>, <class '__main__.B'>,
<class '__main__.C'>, <class '__main__.D'>,
<type 'object'>)
[Finished in 0.1s]
来源: http://www.bubuko.com/infodetail-2485559.html