link:
双下划线
开头和结尾的方法__init__
初始化
方法,可以给一些类的属性值进行初始化return
,否则会报错__init__() should return None,...
__new__(cls, *args, **kwargs)
对象实例化
时调用的第一个
方法类
本身super().__new__(cls, *args, **kwargs)
返回一个新的实例__init__
方法将会被调用__init__
方法__del__
del x
的区别: del x
将x的引用计数器-1
,x.__del__()
仅在引用计数器变为零时调用__del__
会被执行__cmp__(self, other)
__lt__, __gt__, __le__, __ge__, __eq__, __ne__
@total_ordering
__pos__(self), __neg__, __abs__, __invert__
__add__(self, other), __sub__, __mul__, __floordiv__, __div__
__mod__, __pow__, __lshift__, __rshift__, __or__, __xor__
__radd__
,实现反运算__iadd__
,实现增量运算__int__, __float__, __long__, __complex__
__oct__, __hex__, __index__
__str__, __repr__
In[19]: class Base:
...: greeting = "hello world"
...:
...: def __repr__(self):
...: return f"{self.greeting} in English. -- by repr"
...:
In[20]: b=Base()
In[21]: b
Out[22]: hello world in English. -- by repr
__getattribute__(self, item)
return super(Base, self).__getattribute__(item)
返回对象的属性__getattr__(self, name)
__setattr__(self, key, value), __delattr__(self, item)
.
访问、设置、删除属性的时候会触发相应的魔法方法class Base(object):
p = "hello world"
def __getattr__(self, item):
print("__getattr__")
return "error"
def __getattribute__(self, item):
print('__getattribute__')
return super(Base, self).__getattribute__(item)
def __setattr__(self, key, value):
# self.key = value
self.__dict__[key] = value
def __delattr__(self, item):
# del self.item
self.__dict__.pop(item)
if __name__ == '__main__':
b = Base()
print(b.k)
"""返回结果
__getattribute__
__getattr__
error
"""
__len__
__getitem__(self, item)
[]
的方式访问对象的属性__setitem__(self, key, value)
__delitem__(self, key)
__iter__
Iterable
,返回可迭代对象,可以是对象本身self
__next__
Iterator
,返回下一个迭代对象,迭代结束返回StopIteration
__contains__
in
和not in
来测试成员是否存在时候__instancecheck__(self, instance)
isinstance(c, Base)
会调用 type(Base)
的__instancecheck__
方法,所以该方法一般用在元类中__subclasscheck__(self, subclass)
__call__(self, *args, **kwargs)
__enter__(self)
__exit__(self, exc_type, exc_val, exc_tb)
__get__, __set__ 或者 __delete__
任一方法的类称为描述符类,其实例对象便是一个描述符,这些方法称为描述符协议
。实例属性
进行访问时,Python 会按 obj.__dict__ → type(obj).__dict__ → type(obj)的父类.__dict__
(实例属性->类属性->父类属性) 顺序进行查找,如果查找到目标属性并发现是一个描述符,Python 会调用描述符协议来改变默认的控制行为
。@property, @classmethod, @staticmethod 和 super
的底层实现机制。__get__ 和 __set__
的描述符称为数据描述符(data descriptor)
__get__
的称为非数据描述符(non-data descriptor)
obj.__dict__
中有与描述符同名的属性,若描述符是数据描述符,则优先调用描述符,若是非数据描述符,则优先使用obj.__dict__
中属性。__get__(self, instance, owner)
:
self
: 描述符类的实例对象instance
: 使用描述符的类的实例对象owner
: 使用描述符的类__set__(self, instance, value)
self
instance
同上value
设置的值__delete__(self, instance)
# !/usr/bin/env python
# -*- coding: utf-8 -*-
class Base:
p = "hello base."
def __init__(self, data):
self.data = data
def __get__(self, instance, owner):
print("Base __get__")
print(f"self is {self}, instance is {instance}, owner is: {owner}")
return self.data
def __set__(self, instance, value):
print("Base __set__")
print(f"self is {self}, instance is {instance}, value is: {value}")
def __getattribute__(self, item):
print('Base __getattribute__')
return super(Base, self).__getattribute__(item)
class Child:
c = Base("I am child")
# def __init__(self):
# self.c = "I am child in init."
if __name__ == '__main__':
t = Child()
print(t.c)
'''
Base __get__
self is <__main__.Base object at 0x1087a1ef0>, instance is <__main__.Child object at 0x1087a1b70>, owner is: <class '__main__.Child'>
Base __getattribute__
I am child
'''
t.c
按照访问顺序,先找类的实例t的属性c
-> Child的属性c
-> Base的属性c
,找到了Child的属性c
描述符
,调用描述符协议改变调用行为,__get__
-> self.data
-> __getattribute__
(只要访问属性都会调用)# !/usr/bin/env python
# -*- coding: utf-8 -*-
class Base:
p = "hello base."
def __init__(self, data):
self.data = data
def __get__(self, instance, owner):
print("Base __get__")
print(f"self is {self}, instance is {instance}, owner is: {owner}")
return self.data
def __set__(self, instance, value):
print("Base __set__")
print(f"self is {self}, instance is {instance}, value is: {value}")
def __getattribute__(self, item):
print('Base __getattribute__')
return super(Base, self).__getattribute__(item)
class Child:
c = Base("I am child")
def __init__(self):
self.c = "I am child in init."
if __name__ == '__main__':
t = Child()
print(t.c)
'''
Base __set__
self is <__main__.Base object at 0x108dc9a58>, instance is <__main__.Child object at 0x108dc9ef0>, value is: I am child in init.
Base __get__
self is <__main__.Base object at 0x108dc9a58>, instance is <__main__.Child object at 0x108dc9ef0>, owner is: <class '__main__.Child'>
Base __getattribute__
I am child
'''
实例属性c
,实例属性和描述符属性同名,且描述符属于数据描述符,所以调用描述符协议改变默认控制行为self.c
-> __set__
-> __get__
-> __getattribute__
class Base:
p = "hello base."
def __init__(self, data):
self.data = data
def __get__(self, instance, owner):
print("Base __get__")
print(f"self is {self}, instance is {instance}, owner is: {owner}")
return self.data
# def __set__(self, instance, value):
# print("Base __set__")
# print(f"self is {self}, instance is {instance}, value is: {value}")
def __getattribute__(self, item):
print('Base __getattribute__')
return super(Base, self).__getattribute__(item)
def __getattr__(self, item):
print('Base __getattr__')
return "error."
class Child:
c = Base("I am child")
def __init__(self):
self.c = "I am child in init."
if __name__ == '__main__':
t = Child()
print(t.c)
'''
I am child in init.
'''
Base
为非数据描述符,优先使用实例属性