目录
魔术方法:
为编程提供便利,可大大提高编程效率;
pythonic;
特殊属性:
__name__,类、函数、方法等的名字,实例没有此属性;
__module__,类定义所在的模块名;
__class__,对象或类所属的类,如对象的类的类self.__class__.__class__;
__bases__,类的基类的元组,顺序为它们在基类列表中出现的顺序,不是mro;
__doc__,类、函数的文档字符串,如没定义为None;
__mro__,类的mro,class.mro()返回的结果保存在__mro__中,method resolution order,找链,mixin;
single linkedlist中的__getitem__,仅用于容器,提供一种方便的接口,如索引或其它方式来用;
函数中的属性,foo.__defaults__,用元组保存位置参数默认值;
函数中的属性,foo.__kwdefaults__,用元组保存关键字参数默认值;
魔术方法分类:
创建与销毁:__init__、__del__;
hash;
bool;
__repr__、__str__,可视化;
__add__,运算符重载;
单(双)向链表中的[]、__getitem__、__sizeof__,容器和大小;
可调用对象,decorator、类装饰器;
上下文管理,with...as...;
反射(自省);
描述器;
其它杂项;
__dir__
查看属性,返回类或对象的所有成员名称列表;
dir()函数就是调用__dir__(),如果提供__dir__(),则返回属性的列表,否则会尽量从__dict__属性中收集信息;
如果dir(obj),参数obj中包含方法__dir__(),该方法将被调用,如果参数obj不包含__dir__(),该方法将最大限度的收集参数信息;
dir(),对于不同类型的对象有不同的行为:
如果对象是类型或类对象,列表包含类的属性名、及它的基类的属性名;
否则,列表包含对象的属性名、它的类的属性名、类的基类的属性名;(向上逐级找)
例:
In [8]: dir() #搜集当前模块
Out[8]:
['In',
'Out',
'_',
'_1',
'_2',
'_3',
'_4',
'_5',
'_7',
'__',
'___',
'__builtin__',
'__builtins__',
'__doc__',
'__loader__',
'__name__',
……
例:
class A:
def __init__(self,name=18):
self.name = name
class B(A):
def __dir__(self): #实例的,类中的方法要看第1个参数,是self就是实例的
return ['abcdefg'] #必须返回列表,若写为return 'abcd'则返回['a','b','c','d']
b = B()
print(sorted(dir(b)))
print(sorted(dir(B)))
print(sorted(b.__dict__))
print(sorted(B.__dict__))
print(dir()) #pycharm中的dir(),__builtins__内置函数等,如果对象是模块对象,列表包含模块的属性名;
输出:
['abcdefg']
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
['name']
['__dir__', '__doc__', '__module__']
['A', 'B', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'b']
例:
#example_class_magicmethod2.py
class Animal:
X = 123
def __init__(self,name):
self._name = name
self.__age = 10
self.weight = 20
print("animal module's name = {}".format(dir())) #如果对象是模块对象,列表包含模块的属性名;
输出:
animal module's name = ['Animal', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
# example_class_magicmethod3.py
from example_class_magicmethod2 import Animal
import example_class_magicmethod2
class Cat(Animal):
X = 'cat'
Y = 'abcd'
class Dog(Animal):
def __dir__(self):
return ['dog']
print("current module's name = {}".format(dir())) #模块名词空间内的属性
print("example_class_magicmethod2 module's name = {}".format(dir(example_class_magicmethod2))) #指定模块名词空间内的属性
print('~~~~~~~~~~~~~~~~~~')
print("object's __dict__ = {}".format(object.__dict__.keys())) #祖先类object的字典
print('~~~~~~~~~~~~~~~~~~')
print("Animal class's dir() = {}".format(dir(Animal))) #类Animal的dir()
print("Cat class's dir() = {}".format(dir(Cat))) #类Cat的dir()
print("Dog class's dir() = {}".format(dir(Dog)))
print('~~~~~~~~~~~~~~~~~~')
tom = Cat('tom')
print("Cat instance's dir() = {}".format(sorted(dir(tom)))) #实例的dir(),包括tom实例的属性、Cat类属性、祖先类object属性,sorted返回dict的key组成的列表
print("Cat instance's __dir__ = {}".format(sorted(tom.__dir__()))) #同上
print('~~~~~~~~~~~~~~~~~~')
print(sorted(set(tom.__dict__.keys()) | set(Cat.__dict__.keys()) | set(object.__dict__.keys()))) #实例的dir()近似等价于该行的__dict__所有(实例的、所属类的、祖先类的所有属性)属性;一般仅用__dict__就够了,是自己设计的,dir(tom)能查到所有;
print('~~~~~~~~~~~~~~~~~~')
print("Dog class's dir() = {}".format(dir(Dog)))
dog = Dog('snoopy')
print("Dog instance's dir() = {}".format(dir(dog)))
print("Dog instance's __dict__ = {}".format(dog.__dict__))
输出:
current module's name = ['Animal', 'Cat', 'Dog', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'example_class_magicmethod2']
example_class_magicmethod2 module's name = ['Animal', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
~~~~~~~~~~~~~~~~~~
object's __dict__ = dict_keys(['__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__init__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__', '__doc__'])
~~~~~~~~~~~~~~~~~~
Animal class's dir() = ['X', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Cat class's dir() = ['X', 'Y', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Dog class's dir() = ['X', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
~~~~~~~~~~~~~~~~~~
Cat instance's dir() = ['X', 'Y', '_Animal__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_name', 'weight']
Cat instance's __dir__ = ['X', 'Y', '_Animal__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_name', 'weight']
~~~~~~~~~~~~~~~~~~
['X', 'Y', '_Animal__age', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_name', 'weight']
~~~~~~~~~~~~~~~~~~
Dog class's dir() = ['X', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Dog instance's dir() = ['dog']
Dog instance's __dict__ = {'_name': 'snoopy', '_Animal__age': 10, 'weight': 20}
例:
class A:
def __init__(self,name=18):
self.name = name
class B(A):
def __dir__(self):
return ['abcdefg']
b = B()
print('~~~~~~~~~~~~~')
print(sorted(dir(b)))
print(sorted(dir(B))) #与dir(A)相等
print(sorted(dir(A)))
print('~~~~~~~~~~~~~')
print(sorted(b.__dict__))
print(sorted(A.__dict__))
print(sorted(B.__dict__))
print('~~~~~~~~~~~~~')
print(dir())
print(b.__dict__)
输出:
~~~~~~~~~~~~~
['abcdefg']
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
~~~~~~~~~~~~~
['name']
['__dict__', '__doc__', '__init__', '__module__', '__weakref__']
['__dir__', '__doc__', '__module__']
~~~~~~~~~~~~~
['A', 'B', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'b']
{'name': 18}
__hash__
list源码中的;
@staticmethod # known case of __new__ #很少用
def __new__(*args, **kwargs): # real signature unknown
""" Create and return a new object. See help(type) for accurate signature. """
Pass
__hash__ = None #技巧,类中不可hashable写法,不可hash类型就是这样实现的
__hash__,内建函数hash()调用的返回值,只能返回一个整型(返回一个整数),如果定义这个方法,该类的实例就可hashable;
一切对象都有__hash__,来自object,object默认还实现了__eq__方法;
__eq__,对应==操作符,判断2个对象是否相等,返回bool值,若返回None则两个对象相等;
__hash__方法只是返回一个hash值作为set的key,但是去重还需要__eq__来判断2个对象是否相等;
哈希,时间复杂度O(1);
hash值相等,只是hash冲突,不能说明2个对象是相等的,因此,一般来说,提供__hash__方法是为了作为set或dict的key的,所以去重要同时提供这两个方法;
类中要两种同时用,__hash__、__eq__;
可hashable对象必须提供__hash__方法,没有提供的话,isinstance(p1,collections.Hashable)一定为False;
from collections import Hashable
print(Hashable(isinstance(A,Hashable))) #很少用,可否hashable用hash()判断即可
注:
元组里有列表则不可hashable;
def __hash__(self),只能返回整型;
一致性hash,hash环,2^32;
def hash(x):
return x % 3 #return x % 3000000,冲突域大,则冲突可能性小
md5,单向散列,不可逆;
hash,一般在缓存中用,时间复杂度O(1);
缓冲,大坝,匹配生产者和消费者速度;
n个实例得到的hash值一样,hash冲突,dict要解决问题,解决办法:拉链法、开地址法;
__eq__,==,def __eq__(self,other): return None,则两个对象等效(相等);
例:
In [1]: o = [1,2,3]
In [2]: hash(o) #相当于o.__hash__(),等价于None()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-5823e6f515e9> in <module>()
----> 1 hash(o)
TypeError: unhashable type: 'list'
In [3]: o.__hash__()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-36e00a5ab94a> in <module>()
----> 1 o.__hash__()
TypeError: 'NoneType' object is not callable
例:
class A:
def __hash__(self):
return 1 #只能返回整型,否则TypeError: __hash__ method should return an integer
print(hash(A()))
输出:
1
例:
class A:
__hash__ = None #不可hash类型就是这样实现的
print(hash(A()))
输出:
Traceback (most recent call last):
File "/home/python/magedu/projects/cmdb/example_class_magicmethod1.py", line 28, in <module>
print(hash(A()))
TypeError: unhashable type: 'A'
例:
class A:
def __init__(self,name=18):
self.name = name
def __hash__(self): #可hashable,hash冲突(hash值一样)
return 1
lst = [A(),A()]
print(lst)
s = set(lst) #set还作了is判断
print(s)
print(len(s)) #2
for x in s:
print(hash(x))
输出:
[<__main__.A object at 0x7fee3d5f4438>, <__main__.A object at 0x7fee3d5f4b00>]
{<__main__.A object at 0x7fee3d5f4438>, <__main__.A object at 0x7fee3d5f4b00>}
2
1
1
例:
class A:
def __init__(self,name=18):
self.name = name
def __hash__(self): #可hash
return 1
def __eq__(self, other): #去重,两个是否相等,相等set才去重;可hash和去重是两个概念,两个一块用
# return False #等价于上例,两个不相等,len(s)为2
# return True
return self.name == other.name
a = A(4)
b = A(4)
print(a.__dict__)
print(b.__dict__)
lst = [a,b]
print(lst)
s = set(lst)
print(s)
print(len(s)) #1
for x in s:
print(hash(x))
输出:
{'name': 4}
{'name': 4}
[<__main__.A object at 0x7f0a3e3ca438>, <__main__.A object at 0x7f0a3e3ca470>]
{<__main__.A object at 0x7f0a3e3ca438>}
1
1
例:
设计二维坐标类Point,比较2个坐标是否相等?
from collections import Hashable
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __hash__(self):
return hash((self.x,self.y))
def __eq__(self, other):
return self.x == other.x and self.y == other.y
p1 = Point(4,5)
p2 = Point(4,5)
print(hash(p1))
print(hash(p2))
print(p1 is p2) #False
print(p1 == p2) #True
print(set((p1,p2)))
print(isinstance(p2,Hashable)) #True
输出:
3713084879518070856
3713084879518070856
False
True
{<__main__.Point object at 0x7fd0fc7e6b38>}
True
__bool__
内建函数bool(),或对象放在逻辑表达式的位置,调用这个函数返回布尔值;
没有定义__bool__(),就找__len__()返回长度,非0为真;如果__len__()也没有定义,那么所有实例都返回真;
__bool__()和__len__()都没有,恒为True;
empty list、empty set、empty tuple、empty dict,四大皆空,集合类型都为空,等效于False;
__bool__,调所有对象,逐级向上找,object中有__bool__的最简单实现,object上也没,就找__len__,__len__也没有,恒为True,一切皆为真;
有__len__,说明是个容器,里面没有东西说明为空,__len__返回值>=0;
注:
链表中不写__bool__,只写__len__,可实现等效False;
例:
class A:
pass
class B:
def __bool__(self):
# return False
return True
class C:
def __len__(self):
# return 0
return 1
print(bool(A()))
print(bool(B))
print(bool(B()))
print(bool(C()))
print(C().__len__())
print(len(C()))
输出:
True
True
True
True
1
1
可视化
__repr__、__str__;
__repr__,内建函数repr()对一个对象获取字符串表达,如果一个类定义了__repr__()但有定义__str__,那么在请求该类的实例的“非正式”的字符串表示时也将调用__repr__();
__str__,str()函数,内建函数format、print()调用,需要返回对象的字符串表达;
__bytes__,bytes的时候,返回一个对象的bytes表达,即返回bytes对象;
__repr__、__str__都没有,找object(打印内存地址);
没有__str__,找__repr__;
没有__repr__,只有__str__:
str()、format、print使用没问题;
内部打印找object,如print([A()]),显示[<__main__.A object at 0x7f5ac6059470>];
一般__repr__、__str__两个都要,写的一模一样;
技巧,在定义__repr__后,__str__ = __repr__,类似__hash__ = None;
例:
class A:
def __init__(self):
self.a = 'a'
self.b = 'b'
def __repr__(self):
return 'repr: {},{}'.format(self.a,self.b)
def __str__(self):
return 'str: {},{}'.format(self.a,self.b)
print(A()) #print函数使用__str__
print([A()]) #[]使用__str__,但其内部使用__repr__
print(([str(A())])) #[]使用__str__,str()函数也使用__str__
print('str:a,b')
s = 'b'
print(['a'],(s,))
输出:
str: a,b
[repr: a,b]
['str: a,b']
str:a,b
['a'] ('b',)
例2:
class A:
def __init__(self):
self.a = 'a'
self.b = 'b'
# def __repr__(self):
# return 'repr: {},{}'.format(self.a,self.b)
def __str__(self):
return 'str: {},{}'.format(self.a,self.b)
print(A())
print([A()]) #内部调用__repr__(),__repr__()没有则调用object打印内存地址
print(([str(A())]))
print('str:a,b')
s = 'b'
print(['a'],(s,))
输出:
str: a,b
[<__main__.A object at 0x7f5ac6059470>]
['str: a,b']
str:a,b
['a'] ('b',)