Python魔术方法详解

写这个的初衷主要是因为网上充斥的大量的假冒伪劣解释说明
好歹自己试一试再写文章啊! 真的是误人子弟
例如: __ getattr__:获取一个不存在的属性时调用的方法 事实上获取任何属性的时候都会调用这个方法(包括存在和不存在的属性)

1. __init __ 和 __new __

__init__(self)

这个方法是一个对象方法,它主要是用来构建对象属性的
当对象创建的时候,就需要给这个对象赋予属性 这个时候,这个对象就开始自动调用了
by tokiea ()

class A:
  def __init__(self):
    print('开始给对象赋予属性了')

a = A()
__________________________________
`开始给对象赋予属性了`

def __new__(cls, *args, **kwargs):

这个方法是一个类方法,它用来创建对象的
也就是对象创建的时候最先调用的方法
通常会用来做单例模式和对象创建计数
*args, **kwargs是用来接收和传递创建对象时的参数
by tokiea ()

class A:
    def __init__(self, name, age=1):  # 实例方法
        print('开始给对象赋予属性了')
        self.name = name
        self.age = age

    def __new__(cls, *args, **kwargs): # 类方法
        print('开始新建对象了')
        print('我是参数args', args)
        print('我是参数kwargs', kwargs)
        return object.__new__(cls)
        # 必须要有返回值 返回创建出来的实例

a = A('小明', age=2)
__________________________________
`开始新建对象了`
`我是参数args ('小明',)`
`我是参数kwargs {'age': 2}`
`开始给对象赋予属性了`

2.__ getattr__ 和 __ setattr__

很好理解的字面意思
获取属性和设置属性时调用的方法

__getattr__(self, item)

当获取实例化后的对象属性时,会自动调用的方法,好像除了阻止别人直接获取属性之外没特别大的用处了

用了这个方法之后,所有的实例对象属性都是需要在这里返回的,否则就是None值

by tokiea ()

class A:
    def __init__(self, name, age=1):
        self.name = name  # 我想多凑几个字数
        self.age = age

    def __getattr__(self, item):
        print('报告老大,有人在调用我的属性', item)
        if item =='name':
            return '不告诉你'

a = A('小明', age=2)
print(a.name)
print(a.age)
__________________________________
`报告老大,有人在调用我的属性 name`
`不告诉你`

`报告老大,有人在调用我的属性 age`
`None`

__setattr__(self, key, value):

这个方法比__getattr __要好用一些
设置属性的时候调用(当然初始化的时候也会调用一次)
可以用来判断属性设置的值(也可以改变即将设置的属性值)
by tokiea ()

class A:
    def __init__(self, name):
        self.name = name  # 我想多凑几个字数
        self.age = 1

    def __setattr__(self, key, value):
        print('开始给实例对象赋值了', key, value)
        if key == 'age' and value:
            # 这个可以做判断或者改变赋值的操作
            if isinstance(value, int):
                pass
            else:
                print('赋值错误,请填整数类型')

a = A('小明')
a.age = 10
a.age = '十八'
__________________________________
`开始给实例对象赋值了 name 小明`
`开始给实例对象赋值了 age 1`
`开始给实例对象赋值了 age 10`
`开始给实例对象赋值了 age 十八`
`赋值错误,请填整数类型`

3. __ enter __和 __ exit __

__enter__(self)
__exit__(self, exc_type, exc_val, exc_tb)

这两个方法就是用with的时候使用的,上下文管理

而且是 都要有

否则就会报错,差不多就像干将和莫邪,杨过和大雕,缺一不可
三个参数:
exc_type 错误类型
exc_val 错误原因
exc_tb 错误发生的内存地址
by tokiea ()

class A:
    def __init__(self, name):
        self.name = name  # 我想多凑几个字数
        self.age = 1

    def __enter__(self):
        print('我要进去了,嘿嘿嘿')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        print('我要出去了')

a = A('小明')
with a:
    print('我进来了')
    a.age = 1/0   # 0不能做被除数  会报错
__________________________________
`Traceback (most recent call last):`
`我要进去了,嘿嘿嘿`
`我进来了`
 `File ".....................py", line 18, in `
    `a.age = 1/0`
`ZeroDivisionError: division by zero`
``
`division by zero`
``
`我要出去了`

4. __del __

__del__(self)

就是被删除的时候调用的方法
python自带垃圾回收 当对象没有引用的时候就会自动触发垃圾回收 自动调用 __del __ 方法
by tokiea ()

class A:
    def __del__(self):
        print('啊!我被删除了')

a = A()
del a  # 这句 可有可无  因为程序运行结束会自动触发
__________________________________
`啊!我被删除了`

PS 刚好看研究了一下描述符 也写一点吧

__get __ , __set __ 和 __delete __

__get__(self, instance, owner)

看参数 instance 实例 owner 拥有者 就知道一个是拥有者 一个是被拥有 肯定需要两个对象

class A:
    def __get__(self, instance, owner):
        print('A:我被(实例)%s调用了,它属于 %s 类'%(instance,owner))

class B:
    a = A()

b=B()
B.a
b.a
__________________________________
`A:我被(实例)None调用了,它属于  类`
`A:我被(实例)<__main__.B object at 0x0000028F0BC00CC0>调用了,它属于  类`

__set__(self, instance, value)

参数 一个是实例 一个是值

class A:
    def __set__(self, instance, value):
        print('我是A:我监听到了:%s被实例:%s设置成了属性' % (value, instance))

class B:
    pass

a = A()
b = B()

B.a = a  # 把实例对象a 先赋值给 类对象B 的类属性 a
b.a = 12345  # 再把 12345 赋值给实例对象b 的a
print(B.a)
print(b.a)
__________________________________
`我是A:我监听到了:12345被实例:<__main__.B object at 0x0000016923F90CC0>设置成了属性`
`<__main__.A object at 0x0000016923F90C88>`
`<__main__.A object at 0x0000016923F90C88>`

最后发现不管是实例对象b 还是类对象B 它们的a属性都是a实例 即使实例b进行了重新赋值12345的操作,也没能改变实例b的a属性

我想知道为什么 求教大佬

by tokiea ()

__delete__(self, instance)

class A:
    def __delete__(self, instance):
        print('实例对象%s把我删除了'%instance)

class B:
    pass

a = A()
b = B()

B.a = a  # 把实例对象a 先赋值给 类对象B 的类属性 a
b.a = 12345  # 再把 12345 赋值给实例对象b 的a
del b.a
print(b.a)
__________________________________
`实例对象<__main__.B object at 0x0000029510180CC0>把我删除了`
`<__main__.A object at 0x0000029510180C88>`

发现最后a实例没有被b实例删除 而是只调用了a的__delete __方法
by tokiea ()

未完待续 -- tokiea

你可能感兴趣的:(Python魔术方法详解)