魔术方法
在python中,所有以'__'包围的方法都是魔术方法,比如类的初始化方法__init__方法。这也是类中最基本的魔术方法,
通过此方法可以定义对象的属性和行为。在对类进行实例化时,首先调用的是基类的__new__方法,__new__方法会取出cls参数,
然后将传入的其他参数传给__init__方法。
比如定义一个Person类
class Person(object):
def __init__(self,name, age=10)
pass
tom = Person('tommy')
在对Person类进行实例化时,Person类会以实参的形式传到基类的__new__方法中(cls参数),然后__new__方法会将其他的实参传给Person类的__init__方法进行初始化。
构造函数__new__与__init__
__new__方法
1.__new__方法是一个静态方法
2.当__new__方法返回值是对象实例时,才会继续调用__init__方法
3.当无返回时,类的初始化方法__init__不会被调用
4.__new__方法很少使用,即使类创建了此方法,即使创建了也需要使用return super().__new__()来使用基类的__new__方法来创建实例并返回给__init__方法
__inite__方法
1.__new__方法与__init__方法共同工作
2.__new__方法用于创建实例,__init__方法用于初始化实例
3.__init__方法不能返回任何值,或者说是返回None
可视化方法
方法 | 意义 |
---|---|
__str__ | str()函数,format()函数,print()函数调用,需要返回对象的字符串表达。如果没有定义,就调用__repr__方法返回字符串表达。如果__repr__方法没有定义,就直接返回对象的内存地址 |
__repr__ | 内建函数repr()对一个对象获取字符串表达,调用__repr__方法返回字符串表达,如果没定义__repr__则返回对象的内存地址 |
__bytes__ | bytes()函数调用,返回一个对象的bytes表达,即返回bytes对象 |
class Person:
def __init__(self, name, age=15):
self._name = name
self._age = age
def __str__(self):
return 'str: {},{} years old'.format(self._name, self._age)
def __repr__(self):
return 'repr: {},{} years old'.format(self._name, self._age)
def __bytes__(self):
return 'bytes: {} {}'.format(self._name, self._age).encode()
# import json
# return json.dumps(self.__dict__).encode()
tom = Person('tom')
print('{}'.format(Person('tom')))
# print([Person('tom')]) # []使用__str__,但其内部使用__repr__
# print([str(Person('tom'))]) # []使用__str__,其中的元素使用str()函数也调用__str__
# print(bytes(Person('tom')))
print(str(tom)) #有则调用str,否则调用repr,否则返回对象
print(repr(tom)) #有则调用,否则返回对象
print(bytes(tom)) #需要显式调用
__str__方法
1.定义了__str__方法,且显示使用print(), format(), str()时,就会调用__str__方法
2.不使用以上函数时,若已经定义了__repr__方法,则调用__repr__方法
3.不使用以上函数,并且也没有定义__str__方法和__repr__方法时,则直接返回对象的类名和对象的内存地址
__repr__方法
1.当没有定义__str__方法时,使用__repr__方法
2.当__str__方法和__repr__方法都没定义时,直接返回类名和对象的内存地址
__bytes__方法
1.需要显式调用此方法才能将对象以bytes形式输出
hash方法
class collections.abc.Hashable
可hash指的是
:即不可变的数据结构(数字类型(int
,float
,bool
)字符串str
、元组tuple
、自定义类的对象
)。也可以通过id()函数来获取对象修改前后的id号来确定对象是否可hash,如果id号发生改变,说明生成了新的对象,因此这类对象是可hash的(也就是说一旦修改就生成了新对象,标识符从对原对象的引用变成了对新对象的引用,原对象若引用次数为0则可能被销毁)
from collections.abc import Hashable
L1 = [1,2,3]
S1 = {3,4,5}
D1 = {'a':1}
T1 = (1,2)
a = 'xyz'
b = 1
print(1,isinstance(L1, Hashable)) #列表对象不可hash
print(2,isinstance(S1, Hashable)) #集合不可hash
print(3,isinstance(D1, Hashable)) #字典不可hash
print(4,isinstance(T1, Hashable)) #元组可hash
print(5,isinstance(a, Hashable)) #字符串可hash
print(6,isinstance(b, Hashable)) #固定字符,可hash
print(7,isinstance(list, Hashable)) #这个list指的是list类,可hash
print(8,isinstance(set, Hashable)) #指set类,可hash
方法 | 意义 |
---|---|
__hash__ | 调用内建函数hash()的返回值,如果定义了__hash__方法,那么这个类的实例就可hash |
class A:
def __init__(self, name, age=18):
self.name = name
def __hash__(self):
return 1
def __repr__(self):
return self.name
a = A('tom')
b = A('tom')
print(a is b) #False,两个对象地址不同
print(id(a), id(b))
print(hash(a), hash(b), hash(A('tom')))
print(a, b, A('tom'))
set1 = {a, b}
print(set1)
以上示例中,虽然a,b进行hash结果一样,但是由于a,b是两个不同的对象,因此,在集合中可以同时存在。但是会存在hash冲突的现象,若要去除hash冲突另外还需要提供__eq__
方法
__eq__方法
class A:
def __init__(self, name, age=18):
self.name = name
def __hash__(self):
return 1
def __eq__(self, other): # 判断两个对象是否相等(只判断内容)
return self.name == other.name
def __repr__(self):
return self.name
a = A('tom')
b = A('tom')
print(hash(a), hash(b))
s = {hash(a), hash(b)} #去重
print(s)
__eq__
方法判断两个对象的内容是否相等,若相等,则去重。
1.只存在__eq__方法时,类的实例对象是不可hash
2.只存在__hash__方法时,可hash,但是不去重,会存在两个内容相同的对象可加入同一个集合的情况
3.既有__eq__方法和__hash__方法则可hash且会去重
bool方法
方法 | 意义 |
---|---|
__bool__ | 内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值。没有定义__bool__ (),就找 __len__ ()返回长度,非0为真。如果 len ()也没有定义,那么所有实例都返回真 |
class A: pass
a = A()
print(1,bool(A)) #True
print(2,bool(a)) #True
class B:
def __bool__(self):
return False
print(3,bool(B)) #True
print(4,bool(B())) #False
if B():
print('Real B instance')
class C:
def __len__(self):
return 0
print(5,bool(C)) #False
print(6,bool(C())) #True
if C():
print(7,'Real C instance') #False