Python常见的特殊方法
首先来个大体的总览:
1.字符串,字节序列:__repr__、__str__、 __format__、 __bytes__
2.数值转换:__abs__、__bool_、__complex__、__init__、__float__、__hash__、__index__
3.集合模拟:__len__, __getitem__, __setitem__, __delitem__, __contains__
4.可调用模拟:__call__
5.迭代枚举:__iter__, __reversed__, __next__
6.实例创建和销毁:__init__, __new__, __del__
7.属性管理:__getattr__, setattr__, __delattr__, __dir__
8.属性描述符:__prepare__
关键方法讲解:
1.__init__(): 这是在类中最为常见的初始化方法,用于初始化实例。
class B(object):
def __init__(self):
print("this is B")
b = B()
2.__new__(cls): 这是在新式类中才有的,它的一个参数是代表了需要实例化的类,可以使前面声明过的类。
class A(object):
def __init__(self, a):
print("this is B")
def __new__(cls, *args, **kwargs):
print("this is A __new__")
return object.__new__(B, *args, **kwargs)
# return object.__new__(cls, *args, **kwargs) 等同于
# return object.__new__(A, *args, **kwargs)
a = A()
print(type(a))
# 结果:
# this is A __new__
# <class '__main__.B'>
- __new__执行在__init__之前,并且__new__决定是否使用本类的__init__,它可以选择调用其他类的构造方法。
- 如果new返回的不是本类,那么就不会调用该类的构造方法
3.__repr__ 和 __str__:这两种特殊方法基本相似,首先Python原文说一个是给机器看的一个是给人看的,看来网上好多人写的都没咋看明白,我就说说自己的理解。在经过多重测试之下得出一下结论:如果类中同时重写了__str__ 和__repr__,那么通过print()这个函数输出的类会调用str,如果只有repr则会执行repr。 上面得到的是结论,接下来理解一下。打印操作会首先尝试__str__和str内置函数(print运行的内部等价形式),它通常应该返回一个友好的显示。__repr__用于所有其他的环境中:用于交互模式下提示回应以及repr函数,如果没有使用__str__,会使用print和str。它通常应该返回一个编码字符串,可以用来重新创建对象,或者给开发者详细的显示。
class A():
def __init__(self):
return 0
def __str__(self):
print("this is str")
return "str"
def __repr__(self):
print("this si repr")
return "repr"
a = A()
print(a) # 直接输出a会调用__str__
print(repr(a)) # 通过repr()函数执行类中的__repr__
# 输出
# this is str
# str
# this is repr
# repr
4.__call__: 这个函数的主要作用类似于C++中的重载了括号运算符"()", 当对象后面加一个括号后就会执行这个方法,将类实例看做函数。
class A(object):
def __init__(self):
print("this is A")
def __call__(self, *args, **kwargs):
print("this is call")
return "1234456"
a = A()
a()
# 输出:
# this is call
5. __getattr__, __setattr__, __delattr__:如果类重写了getattr,那么通过实例对属性访问时的查找顺序是先__dict__ ,如果dict中不存在这个属性,然后访问 getattr,也就是说getattr是在属性找不到的情况下才会执行。
如果类自定义了__setattr__
方法,当通过实例获取属性尝试赋值时,就会调用__setattr__
。常规的对实例属性赋值,被赋值的属性和值会存入实例属性字典__dict__
中。delattr的用法和setattr一样
class A(object):
def __init__(self, name):
print("this is __init__")
self.name = name
def __getattr__(self, item):
self.name = item
return ("this is getattr " + item)
def __setattr__(self, key, value):
print("set " + key + " = " + value)
self.__dict__[key] = value
def __delattr__(self, key):
return object.__delattr__(self, key)
a = A("liixn") # 在__init__中对name赋值时会调用__setattr__
a.name = "wang" # 通过a.name对属性复制还是会调用__setattr__
a.score = '88' # 通过对不存在dict中的属性复制也是可行的
print(a.id) # 查找不存在于dict中的属性会调用__getattr__
print(a.__dict__) # 查看dict
del a.score
print(a.__dict__)
输出如下:
this is __init__
set name = liixn
set name = wang
set score = 88
set name = id
this is getattr id
{'name': 'id', 'score': '88'}
{'name': 'id'}
6.__len__:一个类的表现类似域列表的时候,可以编写len来返回有多少个元素。
class A(object):
def __init__(self, *args):
print("this is __init__")
self.L = args
def __len__(self):
return len(self.L)
a = A('1', '2', '3')
print(len(a)) # 3
7.__getitem__:通俗的来讲就是实现了(P设为实例) P[key] 这种形式的访问 ,当实例通过P[key]取值时,就会调用__getitem__
注意当访问不存在属性的时候才会调用 __getitem__
class A(object):
def __init__(self, dic):
print("this is __init__")
self.L = dic
def __getitem__(self, item):
print("this is getitem")
return self.L[item] # return 可有可无
dic = {'1': 1, '2': 2, '3':3 }
a = A(dic)
print(a["1"])
输出:
this is __init__
this is getitem
1
8.__setitem__:每当实例以这种形式复制时P[key] = value 都会调用该方法,就算类中不存在某个key,也可以通过这种方式复制,通过查看__dict__可以看到这个key会被新添加。
class A(object):
def __init__(self):
self['a'] = 'aa'
self['b'] = 'bb'
def __getitem__(self, item):
print("this is getitem")
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
a = A()
print(a['a']) # 打印原始的'a'
print(a.__dict__) # 查看dict
a['a'] = 'a1a1' # 修改'a'的值
a['c'] = 'cccc' # 不存在'c'
print(a['c']) # 打印'c'
print(a.__dict__) # 再次查看dict
# 输出
# aaaa
# {'a': 'aaaa', 'b': 'bbbb'}
# cccc
# {'a': 'a1a1', 'b': 'bbbb', 'c': 'cccc'}
9.__delitem__:在对对象使用del P[key]时调用,使用方式大致如下。如果不存在key 则会报错
class A(object):
def __init__(self):
self['a'] = 'aaaa'
self['b'] = 'bbbb'
def __delitem__(self, key):
del self.__dict__[key]
a = A()
print('修改前:', a.__dict__) # 查看dict
del a['a']
print('修改后:', a.__dict__) # 再次查看dict
# 修改前: {'a': 'aaaa', 'b': 'bbbb'}
# 修改后: {'b': 'bbbb'}
10.__iter__与__next__: (这是实现生成器的关键函数)首先我们知道一个普通的实例对象是不具备可迭代功能的,如果你想一个类的实例对象具有list 这类可迭代功能的要求,那么就需要实现一个__iter__以及__next__这个方法。我们可以通过一下方式访问:
class A():
def __init__(self,t):
self.t = t
def __iter__(self):
return self
def __next__(self):
if self.t>5:
raise StopIteration
else:
self.t += 1
return self.t
for i in A(3):
print(i)
# 输出
# 4
# 5
# 6
值得注意的是含有__next__()函数的对象都是一个迭代器,如果没有重写__iter__但是重写了__next__,我们依然可以换种方式对对象遍历:
class A(object):
def __init__(self, data=1):
self.data = data
def __next__(self):
if self.data > 5:
raise StopIteration
else:
self.data += 1
return self.data
a = A()
for i in range(3):
print(a.__next__())
# 2
# 3
# 4