zoukankan      html  css  js  c++  java
  • python中基于descriptor的一些概念

    http://www.cnblogs.com/btchenguang/archive/2012/09/17/2689146.html

    1. 前言

    python在2.2版本中引入了descriptor功能,也正是基于这个功能实现了新式类(new-styel class)的对象模型,同时解决了之前版本中经典类(classic class)系统中出现的多重继承中的MRO(Method Resolution Order)的问题,同时引入了一些新的概念,比如classmethod,staticmethod, super,Property等,这些新功能都是基于descriptor而实现的。总而言之,通过学习descriptor可以更多地了解python的运行机制。
     
    在这里,为文章中使用的词汇做一下说明:
    函数:指的是第一个参数不是self的函数,不在类中定义的函数
    方法:指是的第一个参数是self的函数
    实例:类的对象,instance
    对象模型:就是实现对象行为的整个框架,这里分为经典和新的两种

    2. 新式类与经典类

    首先来了解一下新式类与经典类的区别,从创建方法上可以明显的看出:
    #新式类
    class C(object):
        pass
    #经典类
    class B:
        pass
    

    简单的说,新式类是在创建的时候继承内置object对象(或者是从内置类型,如list,dict等),而经典类是直接声明的。使用dir()方法也可以看出新式类中定义很多新的属性和方法,而经典类好像就2个:

    >>> class C(object):
    ...     pass
    ... 
    >>> class B:
    ...     pass
    ... 
    >>> dir(C)
    ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
    >>> dir(B)
    ['__doc__', '__module__']
    

    这些新的属性和方法都是从object对象中继承过来的 

    2.1 内置的object对象

    内置的object对象是所有内置,object对象定义了一系列特殊的方法实现所有对象的默认行为。
    1. __new__,__init__方法
    这两个方法是用来创建object的子类对象,静态方法__new__()用来创建类的实例,然后再调用
    __init__()来初始化实例。
     
    2. __delattr__, __getattribute__, __setattr__方法
    对象使用这些方法来处理属性的访问
     
    3. __hash__, __repr__, __str__方法
    print(someobj)会调用someobj.__str__(), 如果__str__没有定义,则会调用someobj.__repr__(),
     
    __str__()和__repr__()的区别:
    • 默认的实现是没有任何作用的
    • __repr__的目标是对象信息唯一性
    • __str__的目标是对象信息的可读性
    • 容器对象的__str__一般使用的是对象元素的__repr__
    • 如果重新定义了__repr__,而没有定义__str__,则默认调用__str__时,调用的是__repr__
    • 也就是说好的编程习惯是每一个类都需要重写一个__repr__方法,用于提供对象的可读信息,
    • 而重写__str__方法是可选的。实现__str__方法,一般是需要更加好看的打印效果,比如你要制作
    • 一个报表的时候等。
    可以允许object的子类重载这些方法,或者添加新的方法。
     

    2.2 类的方法

    新的对象模型中提供了两种类级别的方法,静态方法和类方法,在诸多新式类的特性中,也只有类方法这个
    特性, 和经典对象模型实现的功能一样。
     
    创建静态方法的代码如下,使用装饰符@staticmethod进行创建 :
    >>> class A(object):
    ...     @staticmethod
    ...     def foo():
    ...             pass
    ...     def bar(self):
    ...             pass
    ... 
    >>> a = A()
    >>> a.foo
    <function foo at 0x7fb64067d5f0>
    >>> a.bar
    <bound method A.bar of <__main__.A object at 0x7fb640678d90>>
    >>> A.bar
    <unbound method A.bar>
    
    可以看出,不管是 类调用,还是实例调用静态方法,都是指向同一个函数对象
    2.2.2 类方法
    也是可以通过类和它的实例进行调用,不过它是有默认第一个参数,叫做是类对象,一般被
    命名为cls,当然你也可以命名为其它名字,这样就你可以调用类对象的一些操作,
    代码如下,使用装饰符@classmethod创建:

     

    >>> class A(object):
    ...     @staticmethod
    ...     def foo():
    ...             pass
    ...     def bar(self):
    ...             pass
    ... 
    >>> a = A()
    >>> a.foo
    <function foo at 0x7fb64067d5f0>
    >>> a.bar
    <bound method A.bar of <__main__.A object at 0x7fb640678d90>>
    >>> A.bar
    <unbound method A.bar>
    >>> class A(object):
    ...     @classmethod
    ...     def foo(cls):
    ...             print 'class name is',cls.__name__
    ...     @classmethod
    ...     def bar(mycls):
    ...             print 'class name is',mycls.__name__
    ... 
    >>> a = A()
    >>> a.foo
    <bound method type.foo of <class '__main__.A'>>
    >>> a.bar
    <bound method type.bar of <class '__main__.A'>>
    >>> A.foo
    <bound method type.foo of <class '__main__.A'>>
    >>> A.bar
    <bound method type.bar of <class '__main__.A'>>
    >>> a.foo()
    class name is A
    >>> A.foo()
    class name is A
    >>> a.bar()
    class name is A
    >>> A.bar()
    class name is A
    

    2.3 新式类(new-style class)

    新式类除了拥有经典类的全部特性之外,还有一些新的特性。比如__init__发生了变化,
    新增了静态方法__new__
    2.3.1 __init__方法
    据说在python2.4版本以前,使用新式类时,如果类的初始化方法没有定义,调用的
    时候写了多余的参数,编译器不会报错。我现在的python 2.7会报错,还是觉得会报错
    比较好点,下面给出新式类和经典类运行这个例子的情况:
    2.3.2 __new__静态方法
    新式类都有一个__new__的静态方法,它的原型是object.__new__(cls[, ...])
    cls是一个类对象,当你调用C(*args, **kargs)来创建一个类C的实例时,python的内部调用是
    C.__new__(C, *args, **kargs),然后返回值是类C的实例c,在确认
    c是C的实例后,python再调用C.__init__(c, *args, **kargs)来初始化实例c。
    所以调用一个实例c = C(2),实际执行的代码为:
    c = C.__new__(C, 2)
    if isinstance(c, C):
        C.__init__(c, 23)#__init__第一个参数要为实例对象
    

      

     
  • 相关阅读:
    剑指offer(链表)
    设计模式
    谷歌Colab使用(深度学习)
    Consul与python API注册与注销
    【日志收集】之Loki
    【消息队列】之 RabbitMQ安装
    【消息队列】之NSQ安装
    Docker基础
    Python3 , Mysql5.7 , Smb 安装
    SkyWalking部署
  • 原文地址:https://www.cnblogs.com/creazylinux/p/7363751.html
Copyright © 2011-2022 走看看