码迷,mamicode.com
首页 > 编程语言 > 详细

Python面向对象-扩展

时间:2018-02-03 15:49:14      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:技术分享   父类   __weak   语句   line   广度   import   metaclass   lte   

获取对象信息

拿到一个变量,除了用 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版本中,类和类型是不同的,

aClassA的一个实例,

那么a.__class__返回class __main__.ClassA,type(a)返回总是<type ‘instance‘>

而引入新类后,比如ClassB是个新类,bClassB的实例,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中继承的机制是就是一种搜索

那么地,这种搜索是深度优先搜索,还是广度优先搜索呢?

上述的问题也叫做mromethod 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]

Python面向对象-扩展

标签:技术分享   父类   __weak   语句   line   广度   import   metaclass   lte   

原文地址:https://www.cnblogs.com/oneTOinf/p/8409162.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!