热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python3学习(26)--类的量身定制

定制类什么是定制类呢?一般来说,我们的常规类,就是封装一些属性和方法的,然后通过类的实例来访问和调用,仅此而已。你有没有想过,像操作字符串一样操作我们的类实例?有没有想过,像操作

定制类


什么是定制类呢?一般来说,我们的常规类,就是封装一些属性和方法的,然后通过类的实例来访问和调用,仅此而已。你有没有想过,像操作字符串一样操作我们的类实例?有没有想过,像操作迭代器对象那样操作我们的类实例?有没有想过,像调用函数那样调用我们的类实例呢? 等等,这种异想天开的想法在Python中就很贴合实际,因为动态语言的特性,活泼灵活,前面我们讲过,我们可以给一个编译好的类,在其运行期间,动态地绑定类属性或者实例属性(这个不难),当然,你完全可以想到,我们也可以在程序运行时去动态地"创建"一个类(这个就没有那么容易了),下面,我们就先来demo演示一下:


构建方法

__builtin__.type(name, bases, dct)

 

name: 类名

bases: 继承的父类,一个tuple元组,单继承的话,就是单元组,单元组的表示法-->(one,)

dct:一个dict类型,用来作为类的初始化元素。


test.py:

#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-

def hello(self):
    print('hello,',self.name)
def __init__(self,name):
    self.name = name
    
Hello = type('Hello',(object,),{'hello':hello,'__init__':__init__})


上述代码,我们干了两件事,一个是定义了两个方法,一个是利用type函数为我们创建了一个类,Hello。

(1)类名 -- Hello

(2)继承自Object

(3)类的两个元素,一个是hello,一个是__init__,注意他们实际指向的是最外层的两个函数实体


我们验证一下,Hello是不是class类型:




没问题,确实是,那我们是不是可以像操作类一样的操作Hello呢?我们继续验证一下:




像操作字符串一样,操作类实例


__len__


#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-

class Student(object):
    def __init__(self,*args):
        self.names = args
    def __len__(self):
        return len(self.names)
s = Student("Kobe",'Durant','Appleyk')
print(len(s))         #获得实例s中names的长度
print(len('abc'))     #获取字符串abc的长度




根据类实例构造器类实例直接输出类内部重要成员数据


__str__  (或  __repr__)


#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-

class Student(object):
    def __init__(self,name,age):
        self.name = name
        self.age  = age
    def __str__(self):
        return 'my name is : %s,i am %s years old.' %(self.name,self.age)
   
s = Student('Appleyk',26)
print(s)
print(Student('Appleyk',26)) 





使类的实例成为一个可迭代的对象


__iter__

__next__


#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-

from collections import Iterable

class MyList(object): #一个长度等于10的有序列表类
    def __init__(self):
        self.num = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.num>9:
            raise StopIteration #一旦超过长度10,停止迭代(注意,sum的初值从0开始)
        else:
            self.num +=1
        return self.num
 
it = MyList()
print(isinstance(it,Iterable))

我们验证下,it实例是否是可迭代的




我们知道只要是可迭代的对象,都可以使用for循环进行遍历:

修改上述代码如下:


#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-

from __future__ import print_function
from collections import Iterable

class MyList(object):
    def __init__(self):
        self.num = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.num>9:
            raise StopIteration
        else:
            self.num +=1
        return self.num
    
it = MyList()
print(isinstance(it,Iterable))
for n in it:
    print(n,' ',end='')


我们看下输出:




这样的输出结果,你都不敢相信,it是类MyList的一个实例,但是,我们通过__iter__和__next__组合定制MyList类,使得it成为了一个可迭代的对象实例,以至于以假乱真,输出效果相当逼真,但是,我们知道,一个真正的list对象,是可以通过下标(index)进行元素访问的,试问一下,现在的it可以吗? 我们看看下面的尝试:





我们继续定制我们的MyList类,使他的实例可以像真正的list对象一样通过index访问元素


__getitem__


#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-

from __future__ import print_function
from collections import Iterable

class MyList(object):
    def __init__(self):
        self.num = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.num>19:
            raise StopIteration
        else:
            self.num +=2
        return self.num
    def __getitem__(self,index):
        for n in [x*2 for x in range(1,index+2)]:
            self.num = n
        return self.num
 
it = MyList()
print(isinstance(it,Iterable))
for n in it:
    print(n,' ',end='')
    
print()
print(it[0])
print(it[9])
print(it[20])


我们看下输入结果:





现在我们的MyList实例越来越像list了,不但可以for遍历每一个元素,还可以像list那样通过下标访问元素,还能不能模仿的再像点呢?比如我们的list有切片slice操作,我们的实例it行不行呢?由于__getitem__函数,参数index的类型无法确定,如果传入的是一个int对象,那我们就可以根据索引[int]取得相应元素,如果是slice对象呢,我们是不是可以根据[start:stop]切片操作实例it,也取出对应的序列集合呢?当然可以,下面,我们将对类MyList再次优化一下,使得实例it具有切片功能:


#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-

from __future__ import print_function
from collections import Iterable

class MyList(object):
    def __init__(self):
        self.num = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.num>19:
            raise StopIteration
        else:
            self.num +=2
        return self.num
    def __getitem__(self,index):
        if isinstance(index,int):
            for n in [x*2 for x in range(1,index+2)]:
                pass
            return n
        elif isinstance(index,slice):
            start = index.start
            stop  = index.stop
            if start is None:
                start = 0
            L = []
            for n in [x*2 for x in range(1,stop+1)]:
                if n>start*2:
                    L.append(n)
            return L
              
it = MyList()
print(isinstance(it,Iterable))
for n in it:
    print(n,' ',end='')
    
print()
print(it[5])
print(it[:2])
print(it[5:10])





ok,我们看下效果:






我们对比一下,list的切片操作是不是和上述的输出结果一致:




我们知道list索引是有负数一说的,也就是正反下标均可以访问,还有step跳步操作(start:stop:step),针对MyList类,我们暂时还没有增加这些功能(工作量有点大),也就是说,通过类的定制,我们可以让类的实例大变身,感觉跟施了魔法一样,颠覆了我们对于传统静态语言中类实例的映像。


由于,定制类中的__xxx__特性比较多,我们最后再讲一个


__call__


像调用函数那样调用类的实例


#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-
class Student(object):
     def __call__(self,name):
          print('My name is %s.' % name)

s = Student()
s('Appleyk')

我们直接看下结果




我们于是想到了斐波那契数列,我们是不是可以定制一个类,使他的实例可以调用本身,并可以传进去一个参数,控制数列的增长,然后返回给我们一个list,这个list就是一个斐波那契数列,噢啦,我们就借助这个__call__来实现我们的描述:


#!/usr/bin/env Python3
# -*- encoding:UTF-8 -*-
class Fib(object):
     def __init__(self):
          self.a,self.b,self.L = 0,1,[] #初始化前后元素值,以及list对象L为空
     def __call__(self,max):    
          while True:
               self.a, self.b = self.b, self.a + self.b #后一个数等于前两个数之和
               if len(self.L)>=max: #一旦超出给定的长度,循环立刻终止
                    break
               else:
                    self.L.append(self.a)
          return self.L
          
f = Fib()
print(f(10)) #调用实例本身,并传入参数10,得到一个长度为10的斐波那契数列
          

神不神奇,我们且看执行结果再做判定:





什么也不说了,再一次颠覆了我们对于传统类实例对象的理解!


其他定制类的__xxx__用法 本篇就不讲了,有兴趣的朋友,可以查官方文档说明:点击这里



推荐阅读
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • 本文介绍了使用Python解析C语言结构体的方法,包括定义基本类型和结构体类型的字典,并提供了一个示例代码,展示了如何解析C语言结构体。 ... [详细]
  • 十大经典排序算法动图演示+Python实现
    本文介绍了十大经典排序算法的原理、演示和Python实现。排序算法分为内部排序和外部排序,常见的内部排序算法有插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。文章还解释了时间复杂度和稳定性的概念,并提供了相关的名词解释。 ... [详细]
  • 开源Keras Faster RCNN模型介绍及代码结构解析
    本文介绍了开源Keras Faster RCNN模型的环境需求和代码结构,包括FasterRCNN源码解析、RPN与classifier定义、data_generators.py文件的功能以及损失计算。同时提供了该模型的开源地址和安装所需的库。 ... [详细]
  • Python使用Pillow包生成验证码图片的方法
    本文介绍了使用Python中的Pillow包生成验证码图片的方法。通过随机生成数字和符号,并添加干扰象素,生成一幅验证码图片。需要配置好Python环境,并安装Pillow库。代码实现包括导入Pillow包和随机模块,定义随机生成字母、数字和字体颜色的函数。 ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
author-avatar
jeanis
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有