• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
66zhyh99
博客园    首页    新随笔    联系   管理    订阅  订阅

笔记3:python魔法方法

python魔法方法

定义:在Python的类中,以两个下划线开头、两个下划线结尾的方法如:__init__、__str__、__del__

魔术方法在类或对象的某些事件触发后会自动执行,如果希望根据自己的程序定制特殊功能的类,那么就需要对这些方法进行重写。使用这些「魔法方法」,我们可以非常方便地给类添加特殊的功能。

python中常见的魔法方法大致可分为以下几类:

  • 构造与初始化

  • 类的表示

  • 访问控制

  • 比较操作

  • 容器类操作

  • 可调用对象

  • 序列化

我们都知道一个最基本的魔术方法, __init__ 。通过此方法我们可以定义一个对象的初始操作。但当实例化我们定义的类,如x = SomeClass() 的时候, __init__ 并不是第一个被调用的方法。实际上,还有一个叫做 __new__ 的方法,来实例化这个对象。然后给在开始创建时候的初始化函数 来传递参数。在对象生命周期的另一端,也有一个 __del__ 方法。接下来看一看这三个方法:

3.1 __new__() (1)__new__(cls, [...]) 是在一个对象实例化的时候所调用的第一个方法,所以它才是真正意义上的构造方法。 (2)它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法。 (3)__new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用。 (4)__new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string。

 
 
 
 
 
 
 
class Person(object):
​
    def __new__(cls, *args, **kwargs):
        print("__new__()方法被调用了")
        print('这个是*agrs', *args)
        print('这个是kwagrs', **kwargs)
        
        # cls表示这个类,剩余所有的参数传给__init__()方法,
        # 若不返回,则__init__()不会被调用
        return object.__new__(cls)
​
    def __init__(self, name, age):
        print("__init__()方法被调用了")
        self.name = name
        self.age = age
        print(self.name, self.age)
​
p = Person("张三", 20)
​
# Output:
# __new__()方法被调用了
# 这个是*agrs 张三 20
# 这个是kwagrs
# __init__()方法被调用了
# 张三 20
​
 

那__new__()在什么场景使用呢?

答:当我们需要继承内置类时,例如,想要继承 int、str、tuple不可变类型,就无法使用 __init__ 来初始化了,只能通过 __new__ 来初始化数据:下面这个例子实现了一个类,这个类继承了 float,之后就可以对这个类的实例进行计算了。

 
 
 
 
 
 
 
class g(float):
    """千克转克"""
    def __new__(cls, kg):
        return float.__new__(cls, kg * 2)
​
a = g(50) # 50千克转为克
print(a)    # 100
print(a + 100)  # 200 由于继承了float,所以可以直接运算,非常方便!
 

一般情况下,覆写 __new__() 的实现将会使用合适的参数调用其超类的 super().__new__(),并在返回之前修改实例。例如:

 
 
 
 
 
 
 
class demoClass:
    instances_created = 0
    def __new__(cls,*args,**kwargs):
        print("__new__():",cls,args,kwargs)
        instance = super().__new__(cls)
        instance.number = cls.instances_created
        cls.instances_created += 1
        return instance
    def __init__(self,attribute):
        print("__init__():",self,attribute)
        self.attribute = attribute
test1 = demoClass("abc")
test2 = demoClass("xyz")
print(test1.number,test1.instances_created)
print(test2.number,test2.instances_created)
 
 
 
 
 
 
 
 
__new__(): <class '__main__.demoClass'> ('abc',) {}
__init__(): <__main__.demoClass object at 0x0000026FC0DF8080> abc
__new__(): <class '__main__.demoClass'> ('xyz',) {}
__init__(): <__main__.demoClass object at 0x0000026FC0DED358> xyz
0 2
1 2
 

 

__new__() 通常会返回该类的一个实例,但有时也可能会返回其他类的实例,如果发生了这种情况,则会跳过对 __init__() 方法的调用。而在某些情况下(比如需要修改不可变类实例(Python 的某些内置类型)的创建行为),利用这一点会事半功倍。比如:

 
 
 
 
 
 
 
class nonZero(int):
    def __new__(cls,value):
        return super().__new__(cls,value) if value != 0 else None#内建函数
    def __init__(self,skipped_value):
        #此例中会跳过此方法
        print("__init__()")
        super().__init__()
print(type(nonZero(-12)))
print(type(nonZero(0)))
 

返回

 
 
 
 
 
 
 
__init__()
<class '__main__.nonZero'>
<class 'NoneType'>

 

 
posted @ 2022-03-11 19:36  66zhyh99  阅读(65)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3