写这个的初衷主要是因为网上充斥的大量的假冒伪劣解释说明
好歹自己试一试再写文章啊! 真的是误人子弟
例如: __ 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 ()