Python魔法方法

Python魔法方法

简介:什么是魔法方法

  • Python里面的魔法函数,是以带双下划线开头和结尾,可以帮助类增强一些功能。这样方法可以在特定的情况下被Python调用,而几乎不用直接调用。
  • 魔法函数和类本身没有直接关系,和类的父类,object也没有关系。魔法函数可以写到任意一个类中,跟继不继承没有必然的关系。
  • 魔法函数定义了,我们不需要显式的调用它,Python解释器自己会知道什么情况下会调用,我们只需要在使用相应的语法的时候就会调用。

PS:

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

基础魔法方法

  • __init__

最常用的魔法方法,在创建完对象后调用,对当前对象的一些实例初始化,无返回值,我们称之为构造方法
例1

class Demo(object):
    def __init__(self):
        print('调用__init__方法')

    def func(self):
        print('这是一个普通的方法')

d = Demo()

输出

调用__init__方法

这个例子印证了上述:__init__方法在创建对象后被自动调用。
例2

对实例初始化。同样的,类中定义了__init__和func两个方法,但这次我们看到在__init__方法中添加了两个参数n和a,并将这两个值赋给成员属性self.name和self.age,在func方法中则使用了这两个成员属性

PS:

  1. self是在为类编写实例方法的时候,放在变量名第一个位子的占位词。

  2. 在具体应用实例方法里,可以不使用self这个变量。

  3. self,就是指由这个类创造出来的实例

class Demo:
    def __init__(self, n, a):
        self.name = n
        self.age = a

    def func(self):
        print('我的名字是 %s, 我的年龄是 %d'%(self.name, self.age))

d1 = Demo('小明',23)
d1.func()

d2 = Demo('小红',21)
d2.func()

输出

我的名字是 小明, 我的年龄是 23
我的名字是 小红, 我的年龄是 21
  • __new__

new() 是一种负责创建类实例的静态方法,它无需使用 staticmethod 装饰器修饰,且该方法会优先 init() 初始化方法被调用

new()通常用于控制生成一个新实例的过程。它是类级别的方法。

new()至少有一个参数cls,代表要实例化的类。

new()必须有返回值,返回实例化出来的实例。

例3

class Demo:
    def __new__(cls, *args, **kwargs):
        print('调用__new__方法')

    def __init__(self):
        print('调用__init__方法')

d = Demo()

输出

调用__new__方法

确实首先调用了__new__方法,但奇怪的是并没有调用__init__方法,这是为什么呢?实际上,__new__是负责对当前类进行实例化,并将实例返回,并传给__init__方法,__init__方法中的self就是指代__new__传过来的对象,所以再次强调,__init__是实例化后调用的第一个方法。

PSargs和**kwargs是python函数方法的位置参数和关键字参数,当你不确定你的函数里将要传递多少参数时你可以用args,**kwargs 允许你使用没有事先定义的参数名。

例4

def print_func1(*args):
    print(args)

def print_func2(**kwargs):
    print(kwargs)  
    
print_func1(1, 2, '嘿嘿', [])

print_func2(a=1, b=2, c='哈哈', d=[])

输出

(1, 2, '嘿嘿', [])
{'a': 1, 'b': 2, 'c': '哈哈', 'd': []}

例5

class Demo:
    def __new__(cls, *args, **kwargs):
        print('调用__new__方法')
        return object.__new__(cls)

    def __init__(self):
        print('调用__init__方法')

d = Demo()

输出

调用__new__方法
调用__init__方法

在__new__方法中添加了一条return语句,返回object的__new__方法,由于我们自定义的Demo类的父类都是object类,实际上这里是为了返回了父类object生成的对象,然后将此对象传递给__init__的self。因此只有__new__方法正确return了当前类cls的实例,__init__方法才会被调用。特别需要说明的是,__new__方法中一定是返回父类的__new__方法来创建对象,如果返回当前对象会造成死循环。

  • __del__

同__init__方法相反,__del__在对象销毁时被调用,往往用于清除数据或还原环境等操作,比如在类中的其他普通方法中实现了插入数据库的语句,当对象被销毁时我们需要将数据还原,那么这时可以在__del__方法中实现还原数据库数据的功能。__del__被成为析构方法。

例6

class Demo:
    def __init__(self):
        print('调用__init__方法')

    def func(self):
        print('这是一个普通的方法')

    def __del__(self):
        print('调用__del__方法')

d = Demo()
d.func()

输出

调用__init__方法
这是一个普通的方法
调用__del__方法

当d.func()执行后,对象d没有在任何一个地方被继续引用,这时Python的垃圾回收机制会主动回收这个对象,即销毁d,此时自动调用__del__方法。

  • __call__

允许类的一个实例像函数那样被调用。本质上这代表了 x() 和 x.call() 是相同的。注意 call 可以有多个参数,这代表你可以像定义其他任何函数一样,定义 call ,喜欢用多少参数就用多少。

例7

class test:

        def __init__(self):
                self.x = 1

        def __call__(self, x):
               return "value is %s" % x
          
b = test()
print b(100)

输出

value is 100 

属性相关的魔法方法

  • __getattr__

当我们访问一个不存在的属性的时候,会抛出异常,提示我们不存在这个属性。而这个异常就是__getattr__方法抛出的,其原因在于他是访问一个不存在的属性时最后执行的行为。

例8

class A:
    def __init__(self, value):
        self.value = value

    def __getattr__(self, item):
        print("into __getattr__")
        return "can not find"


a = A(10)
print(a.value)
print(a.name)

输出

10
into __getattr__
can not find
  • __setattr__

由于每次类实例进行属性赋值时都会调用__setattr__(),所以可以重载__setattr__()方法,来动态的观察每次实例属性赋值时__dict__()的变化。下面的Fun类重载了__setattr__()方法,并且将实例的属性和属性值作为__dict__的键-值对:
例9

class Fun:
    def __init__(self):
        self.name = "Liu"
        self.age = 12
        self.male = True
        
    def __setattr__(self, key, value):
        print("*"*50)
        print("setting:{},  with:{}".format(key, value))
        print("current __dict__ : {}".format(self.__dict__))
        # 属性注册
        self.__dict__[key] = value
fun = Fun() 

输出

**************************************************
setting:name,  with:Liu
current __dict__ : {}
**************************************************
setting:age,  with:12
current __dict__ : {'name': 'Liu'}
**************************************************
setting:male,  with:True
current __dict__ : {'name': 'Liu', 'age': 12}

通过在__setattr__()中将属性名作为key,并将属性值作为value,添加到了__dict__中,可以看出,init()中三个属性赋值时,每次都会调用一次__setattr__()函数。

  • __delattr__

本函数的作用是删除属性,实现了该函数的类可以用del 命令来删除属性。

例10

class Coordinate:
    def __init__(self):
        self.x = 10
        self.y = -5
        self.z = 0
 
point1 = Coordinate() 
 
print('x = ',point1.x)
print('y = ',point1.y)
print('z = ',point1.z)
 
delattr(Coordinate, 'z')
 
print('--删除 z 属性后--')
print('x = ',point1.x)
print('y = ',point1.y)
 
# 触发错误
print('z = ',point1.z)

输出

('x = ', 10)
('y = ', -5)
('z = ', 0)
--删除 z 属性后--
('x = ', 10)
('y = ', -5)
Traceback (most recent call last):
  File "test.py", line 22, in <module>
    print('z = ',point1.z)
AttributeError: Coordinate instance has no attribute 'z'
  • __len__

len函数被调用后会调用对象的__ len__函数,实现实例对象的内部逻辑

例11

class Foo:
    def __init__(self, ):
        self.a = [1, 3, 5]

    def __len__(self):
        return len(self.a) + 100


f1 = Foo()
print(len(f1))

输出

103

Process finished with exit code 0

参考链接:

Python魔法方法指南: https://pyzh.readthedocs.io/en/latest/python-magic-methods-guide.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值