1、双下方法

定义:双下方法是特殊方法,它是解释器提供的 由双下划线加方法名加双下划线 方法名的具有特殊意义的方法,双下方法主要是python源码程序员使用的,我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。

(1)调用:不同的双下方法有不同的触发方式,

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

<1> __ len__ -- len() 触发

class A(object):

    def __init__(self,name):
        self.name = name
        print("触发了__init__")

    def __len__(self):     # len() 触发
        print("走这里")
        return len(self.name)    # return len("xqrqwr")  str中__len__
        # 必须有返回值,返回值的类型必须是整型

a = A("xqrqwr")
print(len(a))

# str
a = "12345"      # str这个类的实例
lst = [1,2,3,4,4,5,5,5,5] # list这个类的实例
print(len(a))
print(len(lst))

<2> __ hash__ --hash() 触发

class A(object):

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __hash__(self):  # hash()
        hash({1,2,345})  # 可变数据类,不可数据类型
        return 1
        # 必须有返回值,返回值的类型必须是整型

a = A("meet",25)
print(hash(a))

<3> __ str__ --print 或者 str() 触发

class A:

    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def __str__(self):   # print 触发 str()
        print(111)
        return f"姓名:{self.name} 年龄:{self.age} 性别:{self.sex}"
        # 必须有返回值,返回值的类型必须是字符串


a = A("mee",20,"男")
a1 = A("mee1",200,"男1")
str(a)
print(a)
print(a1)


# 以下对比:
a = A("mee",20,"男")
a1 = A("mee2",200,"女")

print(f"姓名:{a.name} 年龄:{a.age} 性别:{a.sex}")   # "姓名:meet 年龄:20 性别:男"
print(f"姓名:{a1.name} 年龄:{a1.age} 性别:{a1.sex}")  # "姓名:meet2 年龄:200 性别:女"

<4> __ repr__ --print 或者 %r 触发

class A:

    def __init__(self):
        pass


    def __repr__(self):   # print触发  %r
        print(1111)
        return "天魔"

    def __str__(self):   # str 优先级高于 repr  两个都存在就只执行str
        return "小元"

a = A()
print("%r"%(a))

<5> __ call__ --对象调用时触发,对象后加括号即:对象() 或者 类()()

class A:

    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):  # 对象()时调用的__call__
        print("走我")
        print(*args, **kwargs)

a = A()
a()

<6> __ eq__ 等于

class A(object):

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __eq__(self, other):     #  a == a1
        if self.name == other.name:
            return True
        else:
            return False

a = A("mee",56)
a1 = A("mee",108)

print(a == a1)

<7> __ del__ 构造方法,当对象在内存中被释放时,自动触发执行

​ 此方法一般情况下无需定义,因为python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为内存的分配和释放都是交给python解释器类执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class A:
    def __init__(self):
        pass

    def __del__(self):    del 触发
        print("删除时执行我")

a = A()

import time
time.sleep(5)
del a

a = 1
b = a
a = b

垃圾回收机制:

    # 80  5/s
    # 引用计数
    # 标记清除
    # 分袋回收 袋一:10 2/h  袋二: 5/3 4h  袋三: 3 20h

<8> __ item__ 系列 可以像操作字典一样操作实例方法

dic["键"] = 值
del dic["键"]
dic["键"]
class A:

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __getitem__(self, item):
        print(self.__dict__)
        print(self.__dict__[item])  # self.__dict__ 获取的就是字典

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __delitem__(self, key):
        del self.__dict__[key]

a = A("meet",58)
a["sex"] = "男"
a["sex"]
del a["sex"]
print(a.__dict__)

<9> __ new__ 单例模式(工厂模式)

​ 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

class A(object):

    def __init__(self,name):  # 初始化
        self.name = name
        print("我是__init__,先走我")

    def __new__(cls, *args, **kwargs):
        print("我是__new__,先走我")
        return "啦啦啦"

a = A("meet")
print("我是谁:",a)
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class A(object):

    def __init__(self,name):  # 初始化
        self.name = name
        print("我是__init__,先走我")

    def __new__(cls, *args, **kwargs):
        obj = object.__new__(A)
        print("我在哪:",obj)
        return obj                   # obj == __init__()

a = A("meet")
print("我是谁:",a)
class A(object):

    def __init__(self,name): # 初识化
        self.name = name


    def __new__(cls, *args, **kwargs):
        obj = object.__new__(A)   # 调用的是object类中的__new__ ,只有object类中的__new__能够创建空间
        return obj   #本质: obj == __init__()     return __init__()  # 触发了__init__方法


a = A("mee")  # a是对象的内存地址
a1 = A("天魔")  # a是对象的内存地址
a2 = A("天阳")  # a是对象的内存地址
print(a.name)
print(a1.name)
print(a2.name)
# 先执行__new__方法再执行__init__方法
class A:
    __a = None  #__a =  0x000001F346079FD0

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __new__(cls, *args, **kwargs):
        if cls.__a is None:
            obj = object.__new__(cls)
            cls.__a = obj
        return cls.__a

a = A("mee",123)  # 地址0x000001F346079FD0
a1 = A("天魔",11)
print(a.name)
print(a1.name)

单例模式:不管创建多少次,使用的都是同一个内存空间

模块的导入,手写的单例模式

实例化对象时发生的事:

创建对象,并开辟对象空间 __ next__

自动执行 __ init方法,隐性的将对象地址传给self

将对象属性封装到对象空间

2、上下文

(1)__ enter__

(2)__ exit__

class my_open:

    def __init__(self,file,mode="r",encoding="utf-8"):
        self.file = file
        self.mode = mode
        self.encoding = encoding

    def __enter__(self):
        self.f = open(self.file,self.mode,encoding=self.encoding)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type,exc_val,exc_tb) # 没有错误时就是None
        self.f.close()


with my_open("a.txt") as ffff:
    for i in ffff:
        print(i)
print(ffff.read(1111))
print(ffff.read())
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄