python的定制类 - vip共享吧
  • 网站首页
  • IT技术笔记
    • Java教程
    • MySql数据库
    • PHP开发
    • Python教程
    • JavaScript
    • SEO优化
    • 常用工具
  • 好资源福利
    • 会员账号共享
  • 网站模板源码
    • 小程序源码
    • 网站源码
  • 共享网络资源
  • 更多功能
    • 留言吐槽
    • 文章归档
    • 我的邻居
    • 史上今日
    • 视频解析
    • 高清壁纸
    • 公告动态
    • 广告合作
    • 关于我们


导航菜单
  • 网站首页
  • IT技术笔记
    • Java教程
    • MySql数据库
    • PHP开发
    • Python教程
    • JavaScript
    • SEO优化
    • 常用工具
  • 好资源福利
    • 会员账号共享
  • 网站模板源码
    • 小程序源码
    • 网站源码
  • 共享网络资源
  • 更多功能
    • 留言吐槽
    • 文章归档
    • 我的邻居
    • 史上今日
    • 视频解析
    • 高清壁纸
    • 公告动态
    • 广告合作
    • 关于我们
Python

python的定制类

2024/9/6 韩俊  Python教程 900 0

在其它高级语言中,我们可以利用语法,自己编程来扩展类和对象的特性,比如在 C++ 中,我们可以做各种运算符重载来实现这种效果,这样很繁琐麻烦,在 Python 中我们可以通过 __xx__ 的形式来扩展类和对象的这种特性。

前面我们已经学习了 __slots__ 起到限制类的对象添加属性的功能,本节我们主要学习其它的 __xx__ 的作用。

使用 __len__ 函数

我们调用 Python 内置的 len 函数作用于 python 内置的容器(str,list,tuple,dict,set)对象,可以得到容器元素的个数, 实际上调用的是容器的 __len__ 函数进行计算的,下面我们以容器 list 为例来说明问题。

mylist = ["hello", 1, (3, 4), {"a": 1, "b": 2}]
print(len(mylist))  # 实际调用的是 mylist.__len__() 函数
print(mylist.__len__())

如果我们想用 Python 内置的 len 函数作用于我们自定义的类,则需要自己在类里面写 __len__ 函数。

class MyObject(object):
    def __init__(self, *data):
        self.__data = data

    def __len__(self):
        return len(self.__data)

myobject = MyObject(4, "hello", [2, 3])
print(len(myobject))

至于 __len__ 函数返回什么值,是由我们自己决定的,但要注意返回值的类型必须是数字类型,如果是数字类型中的 float 类型,则会返回浮点数的整数部分。

class MyObject(object):
    def __init__(self, *data):
        self.__data = data

    def __len__(self):
        return 250  # 必须为数字类型,否则报异常

myobject = MyObject(4, "hello", [2, 3])
print(len(myobject))

使用 __str__ 函数或 __unicode__ 函数

我们定义一个 MyObject 类,然后用 print 函数打印一个 MyObject 类的对象,则打印出一堆 的东西,这个信息主要标注了我们对象的信息,如果我们想让作用在我们对象上的 print 函数输出我们自己自己想输出的信息,则需要在类里面写 __str__ 函数来实现。

class MyObject(object):
    def __init__(self, *data):
        self.__data = data

    def __str__(self):
        return "I'm MyObject"   # 或者 return "I'm MyObject"

myobject = MyObject(4, "hello", [2, 3])
print(myobject)

当然我们也可以返回中文。

class MyObject(object):
    def __init__(self, *data):
        self.__data = data

    def __str__(self):
        return "大嘎好,我系渣渣辉"  # 或者 return u"大嘎好,我系渣渣辉"

myobject = MyObject(4, "hello", [2, 3])
print(myobject)

我们也可以让我们的对象返回的信息像 Python 内置的容器对象返回的信息一样,但要注意返回类型必须为 str 或 unicode 类型。

class MyObject(object):
    def __init__(self, *data):
        self.__data = data

    def __str__(self):
        return str(self.__data)

myobject = MyObject(4, "hello", [2, 3])
print(myobject)

Python 还提供一个 __unicode__ 函数,在 Python2 中该函数用于返回中文,而 __str__ 函数用于返回 ASCII。然而,在 Python3 中, __str__ 即可以返回中文也可以返回 ASCII,而 __unicode__ 函数,我们并不需要使用。

使用 __repr__ 函数

我们在 Python 的交互模式下,定义一个 MyObject 类,然后定义了 __str__ 函数,然后直接敲入对象名称,显式的还是类似于< xx.MyObject object at 0xxxxxxxx > 的东西,这是因为直接显示变量调用的不是 __str__ 函数,而是 __repr__ 函数,两者的区别是 __str__ 函数返回用户看到的字符串,而 __repr__ 函数返回程序开发者看到的字符串,也就是说,__repr__ 函数是为调试服务的。

...class MyObject(object):
...    def __init__(self, *data):
...        self.__data = data
...
...    def __repr__(self):
...        return "I'm MyObject"
...
>>> myobject = MyObject(4, "hello", [2, 3])
>>> myobject
I'm MyObject   # 控制台输出

使用 __iter__ 函数

我们知道 for...in... 只能遍历迭代器,虽然 Python 内置的容器(list,tuple,dict,set)等等都不是迭代器, 但是却都可以用 for ... in 来遍历,我们通过查找源码发现:实际上 for...in... 在第一次遍历这些内置容器时,会先调用 Python 内置的 iter 函数,该 iter 函数会自动调用这些内置容器类内部的 __iter__ 函数,这些内置容器类内部的 __iter__ 函数返回一个迭代器(迭代对象),然后 Python 的 for 循环就会不断调用该迭代器的 __next__ 函数拿到循环的下一个值,直到遇到 StopIteration 异常时退出循环。同样我们也可以在自己定义的类中重写 __iter__ 函数,让该函数返回一个迭代器,以便支持 Python 的 for 循环。

class MyObject(object):
    def __init__(self, *data):
        self.__data = data

    def __iter__(self):
        return iter(self.__data)  # 返回一个迭代器(返回的是元组对象转换的迭代器)

myobject = MyObject(4, "hello", [2, 3])

for item in myobject:
    print(item)

大家仔细观察一下,我们类中的 __iter__ 函数返回的迭代器是一个元组对象(self.__data 是元组对象)构建的迭代器(iter(self.__data)),在 for...in... 的每次遍历中,都是转换为调用这个元组生成的迭代器的 __next__ 函数。当然,我们 也可以自己在类中实现 __next__ 函数,这样,我们的类就成了迭代器。

class MyObject(object):
    def __init__(self, *data):
        self.index = -1
        self.__data = data

    def __iter__(self):
        return self  # 返回自己,自己本身就是迭代器

    def __next__(self):
        self.index += 1
        try:
            return self.__data[self.index]
        except:
            raise StopIteration

myobject = MyObject(4, "hello", [2, 3])

for item in myobject:
    print(item)

为了让大家更清晰的了解迭代器类是如何实现的,我们仔细分析一下上面代码中 for...in... 遍历的过程。

for item in myobject:
    print(item)

######################## Python 解释器把 for...in... 转变成以下代码 ########################
'''
Python 解释器在第一次执行 for...in 语句之前会先调用 Python 内置的 iter 函数,
该 iter 函数会自动调用 MyObject 类的 __iter__ 函数,
我们自己实现 MyObject 类的 __iter__ 函数返回了对象本身,
注意:在此处 it_myobject 就是 myobject。
'''
it_myobject = iter(myobject)

'''
第一次 for...in 时,直接用 item 带入 it_myobject.__next__(),
此时 item 的值为:4
'''
item = it_myobject.__next__()
print(item)

'''
第二次 for...in 时,直接用 item 带入 it_myobject.__next__(),
此时 item 的值为 "hello"
'''
item = it_myobject.__next__()
print(item)

'''
第三次 for...in 时,直接用 item 带入 it_myobject.__next__(),
此时 item 的值为 [2, 3]
'''
item = it_myobject.__next__()
print(item)

'''
第四次 for...in 时,直接用 item 带入 it_myobject.__next__(),
此时越界触发异常,我们在 except 里面处理掉越界异常,并抛出 StopIteration 异常,
for...in... 在遇到 StopIteration 异常后,终止循环。
'''
item = it_myobject.__next__()  # 引发越界异常,我们处理异常,并抛出 StopIteration 异常,for...in... 终止循环。

使用 __getitem__ 函数

如果我们想让自己写的类像 Python 内置的有序集合一样,支持通过对象加下标的形式获取值, 我们可以在类里面写入 __getitem__ 函数来实现。

class MyObject(object):
    def __init__(self, *data):
        self.__data = data

    def __getitem__(self, index):
        return self.__data[index]

myobject = MyObject(4, "hello", [2, 3])
print(myobject[1])

使用 __getattr__ 函数

正常情况下,当我们调用类的属性不存在时就会抛出异常,但是如果我们重写了 __getattr__ 函数 Python 解释器则会调用 __getattr__ 函数来处理不存在的属性。

class Human(object):
    def __init__(self):
        self.age = 18

    def __getattr__(self, attr):
        return attr + "属性不存在"

ruhua = Human()
print(ruhua.age)
print(ruhua.name)

同样如果我们调用的类的方法不存在时,Python 解释器则会调用 __getattr__ 函数来处理不存在的方法,但要注意该函数要返回一个函数。

def myfunc():
    print("该函数不存在")

class Human(object):
    def __init__(self):
        self.age = 18

    def __getattr__(self, attr):
        return myfunc

ruhua = Human()
ruhua.talk()

因为 __getattr__ 函数的第二个形参接收的是不存在的属性或方法名字,我们可以自己灵活的处理我们想处理的不存在的属性或方法。

def myfunc():
    print("你瞅啥")

class Human(object):
    def __init__(self):
        self.age = 18

    def __getattr__(self, attr):
        if attr == "age":
            return 18
        if attr == "talk":
            return myfunc

ruhua = Human()
print(ruhua.age)
ruhua.talk()

使用 __call__ 函数

类的对象可以有自己的属性和方法,当我们调用对象的函数时,我们用对象加上点加上函数名来调用, 如果我们直接通过在对象的后面加上括号调用,则是调用类的 __call__ 函数,这样一来,对象看起来像个函数,我们称之为仿函数或者函数对象。

class MyObject(object):
    def __init__(self):
        pass
    def __call__(self, arg):
        print(arg)

myobject = MyObject()
myobject("hello") # hello

函数对象和函数之间没有本质区别,函数对象其实就是函数,Python 的 callable 函数可以判断一个变量是否是函数,是则返回True反之返回False。

class MyObject(object):
    def __init__(self):
        pass
    def __call__(self, arg):
        pass

myobject = MyObject()
print(callable(myobject)) # true

本节重要知识点

灵活使用定制类。

注意定制类的注意事项。

点赞:0 分享

上一篇
Python多重继承
下一篇
Python中@property的介绍与使用
作者头像 作者名称 作者性别
韩俊

热门推荐

1 Python3的基本数据类型
2 Python3的if条件判断
3 Python3的变量和常量
4 Python中type和元类的用法
5 Python中xml文件处理
6 python中itertools模块详解

评论列表

取消回复

    •  
      Login

      韩俊

      趁你现在还有时间,尽你自己最大的努力,努力做成你最想做的那件事,成为你最想成为的那种人,过着你最想过的那种生活。这个世界永远比你想的要更精彩,不要败给生活。

      退出登陆
      • 10358文章
      • 455评论
      • 80微语
  • 广告赞助

  • 二零二五年07月
    一二三四五六日
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
  • 分类

    • 网站模板源码
    • IT技术笔记
    • 好资源分享
    • 共享网络资源
  • 最新文章

      • 蛋糕跨年祝福语简短独特
        • 元旦祝福语简短儿童
          • 跨年家人聚会祝福语简短
            • 兄弟生日简短祝福语常用
              • 求婚父母祝福语简短精辟
                • 幽默俏皮的祝福语简短
                  • 拍摄国庆祝福语简短
                    • 夏天防暑祝福语大全简短
  • 热门文章

    • 酷狗音乐VIP账号 酷狗音乐会员账号共享2017.01.29更新
    • 芒果tv vip会员账号 芒果tv会员账号共享2017.01.29更新
    • 爱奇艺vip账号 爱奇艺/PPS会员账号共享2016.12.12更新
    • 优酷/土豆vip会员账号 优酷会员账号共享2017.01.29更新
    • 活动:免费获得爱奇艺VIP/PPS会员账号50天以上的使用权!
    • 酷我音乐VIP账号 酷我音乐会员账号共享2016.12.31更新
    • 暴风影音会员账号 暴风影音会员账号共享2016.12.31更新
    • m1905会员账号 m1905会员账号共享2016.10.21更新
  • 最新评论

    • https://www.vipshare8.com/content/templates/meta/Static/images/tx/10.jpg

      你丫的 文章写得太好了 支持下!![F3...

    • https://www.vipshare8.com/content/templates/meta/Static/images/avatar.jpg

      很棒!刚在某网站看到这个,很欣赏,可惜下...

    • https://www.vipshare8.com/content/templates/meta/Api/qqtx.php/?qq=3861064027

      呃呃呃 oooo

    • https://www.vipshare8.com/content/uploadfile/202103/thum-490d1614564497.png

      回复了111:根据激活的时间有一年的有效期!

    • https://www.vipshare8.com/content/templates/meta/Api/qqtx.php/?qq=792480561

      到2025就到期了吗?

    • https://www.vipshare8.com/content/uploadfile/202103/thum-490d1614564497.png

      [blockquote]打卡时间:16:...

    • https://www.vipshare8.com/content/templates/meta/Static/images/tx/7.jpg

      俊哥,想借用迅雷一用!但需要手机验证!看...

    • https://www.vipshare8.com/content/templates/meta/Api/qqtx.php/?qq=3293901900

      感谢大大的分享

    • https://www.vipshare8.com/content/uploadfile/202103/thum-490d1614564497.png

      回复了好奥v:如果没有解析成功,可以切换接口...

    • https://www.vipshare8.com/content/templates/meta/Api/qqtx.php/?qq=131241242441

      现在视频解析网站怎么用不了啦?

  • 网站统计 I 当前在线:358人

    • 本站管理:1位
    • 用户总数:593位
    • 置顶文章:2篇
    • 日志总数:10358篇
    • 微语总数:80条
    • 评论总数:455条
    • 标签总数:83条
    • 页面总数:8页
    • 分类总数:14个
    • 链接总数:16条
    • 运行天数:3730天
    • 最后更新:7月15日
    • 登录
    • 注册
    • 找回
    Copyright © 2025vip共享吧网站地图 网站备案豫ICP备19004194号-1

    免责声明:本站资源仅供用于学习和交流,本站部分素材内容来源于网络,如有侵权/投稿等,请及时联系站长.

    • 首页
    • 秒懂百科 秒懂百科
    • 搜索
    • 史上今日

    大家都在搜

    • 百度文库下载
    • 2345网址导航
    • 喜马拉雅FM会员账号
    • 秒懂百科
    • Java教程
    • 芒果tv会员
    • 微信小程序
    • 手机赚钱软件
    • 土豆vip账号
    • 威客平台
    • seo优化
    • Python
    • qq音乐会员共享
    • 微信小程序源码
    • 掌阅会员账号
    • seo
    • 
    • 