最全面的Python类内置方法简介,Python零基础入门。


前言

与其他语言相比,Python中的类提供了很多双下划线开头和结尾__xxx__的方法,这些方法是Python运行的基础,很多功能背后都是通过调用这些内置方法来实现的。如len()函数调用对象的__len__方法;print(obj)函数调用对象的__str__方法,for item in iterable_obj调用对象的__next__、__iter__方法。

注:由于所有类内置方法都在双下划线开头和结尾,下文描述中,为描述简洁,在无歧义情况下,部分描述中会去掉方法前后双下划线。

在这里插入图片描述


1.__ new__和__init__

new和init这两个方法很容易混淆,平时定义类时,通常使用的都是init方法,很少用到new方法,但他们是有着截然不同的功能的。
new是静态(@staticmethod)方法,用于创建实例对象,方法必须返回一个对象;而init是实例方法,执行实例初始化,在new返回的对象中执行。

new() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.
init called after the instance has been created (by new()), but before it is returned to the caller.

正常类的实例化过程如下。

class Obj(object):
    def __new__(cls):
        print("__new__ in <Obj>")
        return object.__new__(Obj)
    def __init__(self):
        print("__init__ in <Obj>")
        
obj = Obj()
print(type(obj))

# 执行输出
>> __new__ in <Obj>
>> __init__ in <Obj>
>> <class '__main__.Obj'>

如果我们在类的new方法中,返回成其他类型对下,则最终得到的会是新类型。

class OldObj(object):
    def __new__(cls):
        print("__new__ in <OldObj>")
        return object.__new__(NewObj)
    def __init__(self):
        print("__init__ in <OldObj>")
        
class NewObj(object):
    def __init__(self):
        print("__init__ in <NewObj>")
        
obj = OldObj()
print(type(obj))

# 执行输出

>> __new__ in <OldObj>
>> <class '__main__.NewObj'>

这里有个疑问,为什么new执行之后,既没执行OldObj的init方法,也没执行NewObj的init方法。
Python Doc里的说明是:If new() does not return an instance of cls, then the new instance’s init() method will not be invoked.

在应用上,可以通过覆写new方法,来实现单例模式。

class Singleton(object):
    instance = None
    def __new__(cls):
        if not cls.instance:
            cls.instance = object.__new__(cls)
        return cls.instance
        
s1 = Singleton()
s2 = Singleton()

print(s1 == s2) # 输出:True

2.__ str__和__repr__

str和repr都返回一个对象的字符串描述,不过两者的用途不同,str可以理解是给人阅读的,而repr是给程序使用的,官网对repr的描述如下:

repr(obj)
Return the canonical string representation of the object.
For many object types, including most builtins, eval(repr(obj)) == obj.
即:很多情况下,通过repr(obj)输出的数据,可以重建obj对象。

print(obj)、str(obj)方法调用对象的str方法;交互式CLI、repr(obj)、gdb调试时查看对象值返回的是repr,不过和多情况下程序员把str和repr设置为一样__str__ == __ repr__。

3.__ call__

call方法把一个对象变成为可调用对象,即通过obj()直接调用对象时,系统执行的是对象的call方法,实现call方法的对象,callable(obj)返回为True。

class CallObj(object):
    def __call__(self, *args, **kwargs):
        print("__call__")
        
obj = CallObj()
print(callable(obj))
obj() # 调用了对象的__call__方法

应用方面,可以通过call语法糖,简化对象的调用;也可以用户实现call方法的对象替代基于函数的装饰器,简化代码结构。

4.__ iter__和__next__

在Java等强类型的语言中,对象的功能特性必须通过继承或实现接口来实现,比如可迭代的类,必须继承自Iterator或实现Iterable接口,并实现相关的方法。而对于动态语言的Python来说,它属于 鸭子类型,只要一个类实现了iter和next方法,它就是一个可迭代对象。

鸭子类型(英语:duck typing)在程序设计中是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。这个概念的名字来源于由詹姆斯·惠特科姆·莱利提出的鸭子测试.
“鸭子测试”可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

class Iter:
    def __init__(self, max):
        self.max = max
        self.current = 0
 def __iter__(self):
        return self
 def __next__(self):
        if self.current < self.max:
            self.current += 1
 return self.current
        else:
            raise StopIteration("out-of-bounds")
            
for i in Iter(10):
    print(i)

5.__ getitem__、__ setitem__和__delitem__

这三个方法,主要服务于类list、dict类型的数据结构的中括号[]数据操作中,包括下标操作、切片操作、Key值操作等,经过简单测试,发现Python作为一个合格的“鸭子类型”语言,相关方法能接收的参数类型比list、dict提供的更丰富,为展示相关方法可以使用的参数,以下示例只对方法参数进行打印,不实现具体功能逻辑:

class OpItem:
    def __getitem__(self, item):
        print("getitem, args:", item)
    def __setitem__(self, key, value):
        print("setitem, args:", key, value)
    def __delitem__(self, key):
        print("delitem, args:", key)
        
item_test = OpItem()

getitem操作:

# 下标读取操作
item_test[1] # >> getitem, args: 1
# 切片读取操作
item_test[1:10] # >> getitem, args: slice(1, 10, None)
# 带step的切片读取操作
item_test[1:10:2] # >> getitem, args: slice(1, 10, 2)
# 通过key值读取操作
item_test["str_key"] # >> getitem, args: str_key
# 切片为key值,非标操作,方法会忠实的传递参数
item_test["key1":"key2"] # >> getitem, args: slice('key1', 'key2', None)

setitem操作:

# 下标赋值操作
item_test[1] = 99 # >> setitem, args: 1 99
# 切片替换操作
item_test[1:2] = [10, 20] # >> setitem, args: slice(1, 2, None) [10, 20]

delitem操作:

# 下标删除操作
del item_test[5] # >> delitem, args: 5
# 切片删除操作
del item_test[5:10] # >> delitem, args: slice(5, 10, None)

6.__ getattr__、__ setattr__、__ delattr__

这组方法是在框架开发中必备神器。
当访问对象中不存在的属性时,系统会去调用对象的getattr方法,通过对此方法的处理,可以给系统凭空创造出原来不支持的功能。如访问obj.attr1,而obj中不存在attr1时,会触发getattr方法。
setattr在向对象属性设值时触发,如obj.attr1 = 100;delattr在删除属性时触发,如del obj.attr1。

比如在一个ORM的模型中,我们需要把数据库字段相关的属性保存在对象内的dict型字段fields中,实现和对象的其他字段隔离,就可以通过以上三个方法来实现。

class User:
    def __init__(self):
        # 保存数据库表映射字段
        self.__dict__['fields'] = dict()
        # 数据库字段列表
        self.__dict__["fields_list"] = ["name", "age", "address"]
    def __setattr__(self, key, value):
        # 实现通过user.name = xxx 赋值 
        if key in self.fields_list:
            self.__dict__["fields"][key] = value
            return
        self.__dict__[key] = value
    def __getattr__(self, key):
        # 实现通过user.name 取值
        if key in self.fields_list:
            return self.__dict__["fields"][key]
        return self.__dict__[key]
        
user = User()
user.name = "zhangsan"
print(user.__dict__['fields']['name']) # >> zhangsan

在实现了getattr方法的类的内部,对对象属性进行赋值时需要特别注意,很容易引发getattr的无限循环。在init中,对象的所有自定义属性都没有初始化,此时如果对属性赋值,会触发调用setattr方法,访问属性则触发getattr。所以在类内部,最好通过self.__dict__对对象属性进行赋值和取值,避免通过点(.)运算符(self.attr和self.attr = xxx)引发无限循环。

在getattr方法中,如果要获取的属性不存在,应该抛出什么错误?
答案是AttributeError,因为在系统内置函数hasattr和getattr中(这两个函数不带双下划线),只有捕获到AttributeError,hasattr才会返回False,getattr(obj, attr, default)才能返回默认值(default)值。

7.__ getatrribute__

getatrribute是一个属性访问拦截器,会拦截所有对对象属性访问请求,不管属性是否存在,且具有最优先的访问查询顺序。
对象的属性查找顺序如下:
实例的getattribute → 实例对象字典 → 实例所在类字典 → 实例所在类的父类(MRO顺序)字典 → 实例所在类的getattr → 报错

Called unconditionally to implement attribute accesses for instances of the class. If the class also defines __ getattr __ (), the latter will not be called unless __ getattribute __ () either calls it explicitly or raises an AttributeError. This method should return the (computed) attribute value or raise an AttributeError exception. In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.__ getattribute __(self, name).
既然getattribute会拦截所有属性的访问,那如果我们对于不存在的属性,想要调用getattr来处理,该怎么办呢?
答案是raise AttributeError,只要抛出此错误,就会触发getattr方法的调用。

getattr示例中,我们通过直接访问self.__ dict__来规避触发getattr方法,但是getattribute在访问对象的已有属性时都会触发,即使是self. __ dict __ 也会引发无限循环,所以getattribute方法中不能使用self.__ dict __ ,解决办法是调用父类的getattribute方法,即在getattribute中通过super().__ getattribute __(item)来读取对象的属性。

8.__ enter__和__exit__

enter和exit可以让对象通过with关键字来进行使用,提供进入with块前的初始化工作和退出with块后的清理工作,常用于文件和数据库操作中。

class DbConnect:
    def connect(self):
        print("Init and connect to db.")
    def execute(self):
        print("Execute SQL statement.")
    def disconnect(self):
        print("Disconnect from db.")
    def __enter__(self):
        self.connect()
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.disconnect()
        
with DbConnect() as conn:
    conn.execute()

# 输出
# >> Init and connect to db.
# >> Execute SQL statement.
# >> Disconnect from db.

总结

目前就到这了,注:由于编辑器原因,下划线前后应无空格。


关于Python技术储备

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

👉CSDN大礼包:《Python入门资料&实战源码&安装工具】免费领取安全链接,放心点击

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
在这里插入图片描述

二、Python基础学习视频

② 路线对应学习视频

还有很多适合0基础入门的学习视频,有了这些视频,轻轻松松上手Python~在这里插入图片描述
在这里插入图片描述

③练习题

每节视频课后,都有对应的练习题哦,可以检验学习成果哈哈!
在这里插入图片描述
因篇幅有限,仅展示部分资料

三、精品Python学习书籍

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
在这里插入图片描述

四、Python工具包+项目源码合集

①Python工具包

学习Python常用的开发软件都在这里了!每个都有详细的安装教程,保证你可以安装成功哦!
在这里插入图片描述

②Python实战案例

光学理论是没用的,要学会跟着一起敲代码,动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。100+实战案例源码等你来拿!
在这里插入图片描述

③Python小游戏源码

如果觉得上面的实战案例有点枯燥,可以试试自己用Python编写小游戏,让你的学习过程中增添一点趣味!
在这里插入图片描述

五、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
在这里插入图片描述
在这里插入图片描述

六、Python兼职渠道

而且学会Python以后,还可以在各大兼职平台接单赚钱,各种兼职渠道+兼职注意事项+如何和客户沟通,我都整理成文档了。
在这里插入图片描述
在这里插入图片描述
这份完整版的Python全套学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值