zoukankan      html  css  js  c++  java
  • PythonI/O进阶学习笔记_2.魔法函数

    前言:

    本文一切观点和测试代码是在python3的基础上。

    Content:

    1.什么是魔法函数,魔法函数__getitem__在python中应用。

    2.python的数据模型和数据模型这种设计对python的影响

    3.python常用的魔法函数

    4.从len()方法看魔法函数的特点

    5.魔法函数知识小结

    一   python的魔法函数

    1.什么是魔法函数?

    • 魔法函数是Python中定义的,以__开头,__结尾,形如__fun__()的函数,一般使用已经定义好了的即可。
    • 使用这样一些函数,可以让我们自定义的类有更加强大的特性。
    • 魔法函数一般是隐式调用的,不需要我们显示调用。(即python解释器帮我们调用实现)

    2.如何使用魔法函数?

     例:我们建立一个公司类,里面有员工列表属性。需要循环打印所有员工。

    普通方法为:

    1 class Company:
    2     def __init__(self,employee_list):
    3         self.employee=employee_list
    4 user_list=['ttr1','ttrr2','ttrr3']
    5 company=Company(user_list)
    6 for i in company.employee:
    7     print(i)

    如果说我们用python一个内置的魔法函数的话:

    user_list=['ttr1','ttrr2','ttrr3']
    company=Company(user_list)
    
    
    class Company_Magic:
        def __init__(self,employee_list):
            self.employee_list=employee_list
        def __getitem__(self, item):
            return self.employee_list[item]
    
    company2=Company_Magic(user_list)
    for i in company2:
        print(i)

    区别:第二种直接对对象进行了for循环,第一种对对象里面的一个属性(list)进行循环。

               就是第二种Company_Magic类生成的对象,是有可以迭代这个特性的。

        因为__getitem__帮我们实现了一个逻辑,每次我们实现for循环的时候,for会去找company2这个对象中的__getitem__方法(实际上是先找另外一个迭代方法),并且传入0、1、2...直到抛了异常然后结束。这是解释器帮我们实现的功能。

    ps.想想看如果__getitem__这个函数不管传入什么item都不报异常会怎么样?

    二  python的数据模型和数据模型这种设计模式赋予python的特性

    1.什么是数据模型?

    数据模型其实是对 Python 框架的描述,它规范了这门语言自身构建模块的接口,这些模块包括但不限于序列、迭代器、函数、类等。

    而魔法函数就是数据模型的一个概念。java中常被叫魔术方法,python常叫数据模型。

    2.数据模型对python的影响

    • 魔法函数不属于定义它的那个类,只是增强了类的一些功能。
    • 实现了特定的魔法函数之后,某些操作会变得特别简单。
    • 我们可以采用实现魔法函数来灵活地设计我们需要的类。

    这点是很重要的需要明白python的类有些特性是可以被灵活设计的,只要在编码中让它遵循了某种特定的协议(魔法函数)。

    三 python常用的魔法函数

    __init__:最常用。

    __str__:被print函数调用;这个魔法函数必须返回为string,否则抛异常。

    (我记得最开始初学python调用mongodb对象的什么方法来着,返回的数据用print出来的字符串一直没问题,但是做处理的时候一直说数据格式有误,就是因为传回来的数据对象做了__str__处理。)

    __len__:可以对对象使用 len()函数。在dict、list等类型中也实现了这个方法。

    在pycharm中,输入dict() ,用ctrl+B 跳到dict的定义,可以看到dict具有哪些魔法方法。或者用dir({})也可以看到。

    还有很多比较重要的魔法方法例如 __setattr__() 、__getattr__()、__setitem__()、__getitem__()、__iter__() 超多简化我们编程的魔法函数。

    四  用__len__看魔法函数大致做了哪些事情?

    在三中我们看到,dict()的定义中的魔法函数__len__()定义的内容为空,list()也是。

    实际上,我们在这里看到的相当于只是一个接口的定义而已,真正的实现是在cpython中。

    为了加快len()的速度,比如list、dict、set类型,实际上会走一个捷径。在cpython中,list、dict、set等内置类型是用c实现的,会在c数据结构内部有个参数用来存储数据的长度,len()是直接去读数据结构的长度。所以复杂度是O(1)。
     
    以下为拓展,可不看:

    有关 list 定义源码位置在 Python 目录下的 include/listobject.h 内, 代码如下:

    typedef struct {
        PyObject_VAR_HEAD
        /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
        PyObject **ob_item;
    
        /* ob_item contains space for 'allocated' elements.  The number
         * currently in use is ob_size.
         * Invariants:
         *     0 <= ob_size <= allocated
         *     len(list) == ob_size
         *     ob_item == NULL implies ob_size == allocated == 0
         * list.sort() temporarily sets allocated to -1 to detect mutations.
         *
         * Items must normally not be NULL, except during construction when
         * the list is not yet visible outside the function that builds it.
         */
        Py_ssize_t allocated;
    } PyListObject;

    其中 ob_item 是指向列表元素的指针数组, list[0] 即 ob_item[0], allocated 是列表的空间大小。在 PyObject_VAR_HEAD 中, 拥有一个 ob_size 变量。

    下面是 Python 目录下的 include/object.h 中的相关代码:

    #define PyObject_VAR_HEAD      PyVarObject ob_base;
    ...
    ...
    typedef struct {
        PyObject ob_base;
        Py_ssize_t ob_size; /* Number of items in variable part */
    } PyVarObject;

    ob_size 变量存储的就是对象的长度, 所以每次调用 _len_() 方法的时候, 返回的是一个已经存储好了的变量,

     
    小结:魔法函数大部分都做了很多优化的事情,设计理念还是比较重要的。

     五  总结

    魔法函数是贯穿所有python知识点的。
    可以用魔法函数来组织自己脑子里python知识点的知识树。
    • 魔法函数是内置的前面为__的方法
    • 魔法函数是不需要显示调用的,python语法本身会隐含调用魔法函数
    • 魔法函数和对象不存在继承关系,任何对象都可以定义魔法函数
    • 魔法函数让python的各种类型组织起来了,让对象有数据类型,比如增加一个迭代类型等
    • __str__\__repr__\__add__等等多种常用魔法函数熟知会让代码更pythonic
    • python解释器其实会经可能提高很多效率,让开发者灵活性变高
     
     
  • 相关阅读:
    20145301&20145321&20145335实验三
    20145301《信息安全系统设计基础》第12周学习总结
    20145301&20145321&20145335实验五
    20145240 《信息安全系统设计基础》课程总结
    20145240《信息安全系统设计基础》第十四周学习总结
    20145240《信息安全系统设计基础》第十三周学习总结
    20145240 《信息安全系统设计基础》第六周同学问题总结
    20145240 GDB调试汇编堆栈过程分析
    20145240 《信息安全系统设计基础》实验五 网络通信
    20145240《信息安全系统设计基础》实验四 驱动程序设计
  • 原文地址:https://www.cnblogs.com/besttr/p/11324780.html
Copyright © 2011-2022 走看看