Python的魔法函数

1. 什么是魔法函数

  Python的类中有很多内置的魔法函数,他们以__开始和结束,如__init__,__str__等等,它是未来增强类的特性,不需要专门调用,在特定的场合下Python会自己调用,不能自己定义魔法函数

 

2. 常用的魔法函数

1. 字符串表示
  1. __str__:在print的情况下,可以返回友好的内容显示,python环境下直接运行返回指针地址
  2. __repr__:不管是print或者直接执行,都会返回直接的内容显示
复制代码
class Label:
    def __init__(self, value='hello world'):
        self.value = value

label = Label()
# 在cmd的python环境下才能输出,在py编辑器无输出
# 但他们都只是指向了一个地址,显然这不是我们想要的结果
lable                     # <__main__.Label at 0x2128207e448>
print(label)             #  <__main__.Label object at 0x000002128207E448>
 
# __str__:面向用户编程,在print下输出内容
class Label:
    def __init__(self, value='hello world'):
        self.value = value

    def __str__(self):
        return self.value

label = Label()   
# __str__只能在print的情况下才能输出具体想要的效果 
label                # <__main__.Label at 0x212827fdcc8>
print(label)         # hello world

# __repr__:面向程序员编程,不管是print还是直接运行的情况下,都能输出内容
class Label:
    def __init__(self, value='hello world'):
        self.value = value

    def __repr__(self):
        return self.value

label = Label()
# 输出结果直观
label                    # hello world
print(label)             # hello world
复制代码

 

2. 集合序列相关

  1. __len__: 计算对象容器中元素的个数

复制代码
class Weekly:
    def __init__(self,my_list):
        self.my_list = my_list

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

weekly = Weekly([1,2,3,4,5])
# 如果没有__len__函数,执行len方法时报错
print(len(weekly))              # 5
复制代码

 

  2. __setitem__、__getitem__和__delitem__

复制代码
class A:
    def __init__(self):
        self.dict = {}
    
    # --__setitem__--,新建字典
     def __setitem__(self, key, value):
        self.dict[key] = value

    # --__getitem__--,通过字典key获取value
    def __getitem__(self, item):
        return self.dict[item]
  # --__delitem__--,删除对应key的记录
    def __delitem__(self, key):
        self.dict[key]
a = A() 
a.dict[
'name'] = 'timi'       # 调用了setitem方法
a['age'] = 22             # dict省略,一样的结果
print(a.dict)             # {'name': 'miti', 'age': 12}
print(a['name']            # 调用getitem方法 timi
del a['age']              # del函数必须调用__delitem__方法
print(a.__dict__)           # {'dict': {'name': 'miti'}}
复制代码

 

  3. __contains__:查找属性是否在class中

复制代码
class H:
    def __init__(self, data):
        self.data = data

    # 判断item是否存在class的data中,是返回True,不是返回False
    def __contains__(self, item):
        return item in self.data


h = H(['a', 'b', 'c', 'd'])
print('b' in h)  # True
print('f' in h)  # False
复制代码

 

3. 迭代相关

  1. __iter__和__next__:迭代器

复制代码
class Iterator:
    def __init__(self, value):
        self.start = 0
        self.end = value

    def __iter__(self):
        return self

    def __next__(self):
        if self.start < self.end:
            self.start += 1
            return self.start
        else:
            raise StopIteration

iterator = Iterator(5)
# 可使用for循环遍历
for i in iterator:
    print(i, end=' ')        # 1 2 3 4 5

# 可以使用next函数遍历
print(next(iterator))      # 1
print(next(iterator))      # 2
print(next(iterator))      # 3
print(next(iterator))      # 4
print(next(iterator))      # 5
复制代码

 

4. 实现调用方法

  1. __call__: 实现类对象像普通函数那样可调用

复制代码
class Call:
    def __init__(self, name):
        self.name = name

    def __call__(self, age):
        print(f'我叫{self.name},今年{age}岁。')

call = Call('Tom')        # 类实例化对象时传参形式
call(22)                      # call方法的传参,类似于普通函数调用
复制代码

 

5. 上下文管理器(with)

  1. __enter__和__exit__: 实现with上下文管理器调用

复制代码
class Open:
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        self.f = open(self.filename, 'r')
        return self.f           # 如果不返回,则返回一个None
    #
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()

openTest = Open(r'E:\Python\file.txt')
# with开始运行时,会调用__enter__()方法,运行结束后,会调用__exit__()方法
with openTest as f:
    print(f.read())
复制代码

    

 6. 元类相关

  1. __init__:构造函数,初始化对象,类在生成对象时默认被调用

复制代码
class Init:
  def __init__(self,name,age):
    self.name = name
    self.age = age

  def say(self):    # 调用init方法
    return (f'他叫{self.name},今年{self.age}岁')

init = Init('Tom',22)
init1 = Init('miki', 30)
print(init.say())   # 他叫Tom,今年22岁
print(init1.say())  # 他叫miki,今年30岁
复制代码

 

  2. __new__:负责类的创建,在__init__之前执行

复制代码
1.在类实例化之前调用,最先调用并返回类实例,一般不建议重写__new__除非是在str,int或者tuple不可变类型的子类时
2.在__init__之前被创建,它必须要有一个参数cls,表示要返回的实例化类
3.new的返回值是一个对象,也就是init中的self
4.必须要return出new函数才能执行init函数,否则返回None

# # __new__ 在new的返回值和self的值时一样的,也就是说new返回的是self
class Animal(object):
  def __init__(self):
    pass

class Capstr():
  # 在重写__new__()方法时,需要在参数中加入*args,**kwargs,或者显式地加入对应的参数,才能通过__init__()方法初始化参数
  def __new__(cls, *args, **kwargs):  # or def __new__(cls, name)
    print('new_cap')
    # 构造一个类实例,并传递给__init__方法
    instance = super().__new__(cls)
    print(id(instance))                  # 2676307354184
    return instance
  # 如果__new__()方法返回一个其他类的实例的话,那它自身的__init__()方法将不会被调用。而且,new()方法将会初始化一个其他类的对象
  # return Animal()

  def __init__(self, name):
    self.name = name
    print('init_cap')
    print(id(self))                       # 2676307354184

# 先调用__new__方法,在调用__init__方法
cap = Capstr('timo')
print(id(cap))                            # 2676307354184
# 返回其他类时
print(type(cap))            # <class '__main__.Animal'>
print(cap)                  # <__main__.Animal object at 0x10fea3550>                                                   
复制代码

 

7. 数值相关

  1. __abs__:执行abs是自动调用class类中的__abs__方法,返回一个绝对值

class Abs:
    def __init__(self, x):
        self.x = x

    def __abs__(self):
        return abs(self.x)

print(abs(Abs(-33)))      # 33

 

  2. __bool__:执行bool函数时调用__bool__方法,返回的是一个布尔值

复制代码
# 当对象为int类型时,值为0返回False,否则返回True
print(bool(0))      # False
print(bool(1))      # True

# 当对象为str类型是,str类当中没有__bool__方法,默认调用__len__方法,当长度为0时,返回False,否则返回True
# 列表,元组,字典,集合亦是如此
print(bool(''))     # False
print(bool('a'))    # True

# 当对象是类实例化对象时,默认返回True
class A:
    def __init__(self, x):
        self.x = x

print(bool(A(0)))           # True
print(bool(A('a')))         # True

# 在class类内部重新定义__bool__方法
class B:
    def __init__(self, x):
        self.x = x

    def __bool__(self):
        if self.x > 5:
            return True
        return False

print(bool(B(2)))           # False
print(bool(B(6)))           # True

# 如果class类中没有定义__bool__函数,则会去调用__len__方法
class C:
    def __init__(self, value):
        self.length = value

    def __len__(self):
        return self.length

print(bool(C('a')))         # True
print(bool(C(0)))           # False
print(bool(C(1)))           # True
复制代码

 

  3. __int__和__float__方法:执行int或float方法的时候会去调用类内部的__int__或__float__方法

复制代码
class IntAndFloat:
    def __init__(self, x):
        self.x = x

    def __int__(self):
        return (int(self.x))

    def __float__(self):
        return float(self.x)

print(type(int(IntAndFloat('123'))),int(IntAndFloat('123')))        # <class 'int'> 123
print(type(float(IntAndFloat('123'))),float(IntAndFloat('123')))    # <class 'float'> 123.0
复制代码

 

  4. __hash__:哈希返回值

复制代码
class Hash:
    def __init__(self, name):
        self.name = name

    # 通过重写__hash__的返回值,返回值只能是整数
    def __hash__(self):
        return 123
# hash方法在执行类实例的时候,会调用class类中的__hash__方法
print(hash(Hash('timi')))       # 123
复制代码

 

8. 属性相关

  1. __setattr__、__getattr__和__getattebute__

复制代码
class Attr:
    def __init__(self):
        pass

    def __setattr__(self, key, value):
        # self.name = value    不能直接进行赋值,否则进入死循环(递归)
        self.__dict__[key] = value

    def __getattr__(self, name):
        print('访问不存在key时,触发__getattr__方法')
        return self.__dict__[name]

    # 属性拦截器,当实例对象的属性被访问的时候都会触发__getattribute__方法
    def __getattribute__(self, item):
        print('key无论存不存在,都会触发__getattrbute__方法')
        return super().__getattribute__(item)

attr = Attr()
attr.name = 'momo'              # 调用__setattr__方法和__getattribute__方法
print(attr.name)                # 调用__getattr__方法和__getattribute__方法
attr.a                          # 访问不存在key时,触发__getattr__方法和__getattribute__方法
复制代码

 

posted @   无敌小豆包  阅读(336)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示