目录
一、new方法
__init__()
是初始化方法,__new__()
方法是构造方法,创建一个新的对象
实例化对象的时候,调用__init__()
初始化之前,先调用了__new__()
方法
__new__()
必须要有返回值,返回实例化出来的实例
def __new__(cls, *args, **kwargs):
例子
# -*- coding: utf-8 -*-
class Foo(object):
def __init__(self,name):
self.name=name
def __new__(cls, *args, **kwargs):
obj=super(Foo, cls).__new__(cls) #利用object的__new__方法创建新的空对象
obj.__init__(*args,**kwargs)
return obj
f=Foo('nike')
print(f.name)
print(f.__dict__)
二、__len__方法
如果一个类表现得像一个list,要获取有多少个元素,就得用 __len__()
函数。
通过len(object)调用
class Student():
def __init__(self,*args):
self.names = args
def __len__(self):
return len(self.names)
s = Student("nick","jack","pony")
print(len(s)) #用len直接调用__len__方法
from collections import namedtuple
Card = namedtuple("Card",["rank","suit"]) #这里相当于创建了一个名为Card的类,后面的列表里是类的类属性,没有函数属性
#
class FranchDeck:
ranks = [str(n) for n in range(2,11)] + list('JQKA')
suits = ['红心','方板','梅花','黑桃']
def __init__(self):
self._cards = [(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] #这里是一个列表生成式,
#将第一个for循环里的值赋值给rank,将第二个for循环里的值赋给suit,这个类只要一实例化就自动生成了一副除了没有大小王的牌
#每张牌都是用元组来表示的
def __len__(self):
return len(self._cards) # choice()方法依赖__len__(self)
def __getitem__(self, item):
return self._cards[item]
def __setitem__(self, key, value):
self._cards[key] = value
deck = FranchDeck() #这里相当于创建了一副牌
print(deck[0]) #打印第一张牌
print(deck[2:5]) #打印第2-4张牌
from random import choice,shuffle
print(choice(deck)) #随机抽取一张牌
shuffle(deck) #洗牌
print("洗牌后的第一张",deck[0]) #打印第一张牌
三、__eq__
方法
__eq__(slef,other)
,判断self对象是否等于other对象,使用==或者is调用此方法。
class Foo:
def __init__(self,name):
self.name = name
def __eq__(self, other):
if self.name == other.name: #判断如果对象的name属性相等就返回True
return True
else:
return False
obj1 = Foo("nick")
obj2 = Foo("nicholas")
print(obj1 is obj2)
四、__hash__
方法
获取取一个对象的哈希值,一般来说,对于对象的hash值是基于对象的内存地址生成的,但是重写__hash__
方法可以自己定制hash取值的对象
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
def __hash__(self):
return hash(self.name+str(self.age)) #这里基于对象的两个属性返回hash值
obj1 = Foo("nick",18) #注意hash的对象不能是整数
obj2 = Foo("nick",18)
print(hash(obj1))
print(hash(obj2))
注意魔法方法__hash__的使用场景有二:
(1)被内置函数hash()调用
(2)hash类型的集合对自身成员的hash操作:set(), frozenset([iterable]), dict(**kwarg)
五、__eq__和__hash__应用
1. 以下代码前半段只用到了__eq__,因为没涉及可hash集合,也就没有涉及到hash
2、如果自定义类重写了__eq__()方法没有重写__hash__()方法,那么这个类无法作为哈希集合的元素使用(这个hashable collections指的是set、frozenset和dict)
比如哈希集合放的全是对象,只定义的__eq__,没定义__hash__,会报错
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# def __hash__(self):
# print(self.name, '使用了__hash__方法')
# return hash(self.name)
def __eq__(self, other):
print(self.name, '使用了__eq__方法')
return self.__dict__ == other.__dict__
person1 = Person('zs', 20)
person2 = Person('ls', 20)
person3 = Person('ww', 30)
person4 = Person('zs', 20)
print(person1 == person4)
print(person2 == person3)
set1 = {person1, person2, person3, person4}
print(set1)
输出:
zs 使用了__eq__方法
True
ls 使用了__eq__方法
False
Traceback (most recent call last):
File "D:/self_study/python_study/class_study/python——内置方法.py", line 88, in <module>
set1 = {person1, person2, person3, person4}
TypeError: unhashable type: 'Person'
这其实是因为重写__eq__()方法后会默认把__hash__赋为None(文档后面有说),像list一样。如下面测试:
class A:
def __eq__(self, other):
pass
a = A()
print(a.__hash__)
hash(a)
输出:
None
TypeError: unhashable type: 'A'
3. 如果自定义类重写了__hash__()方法没有重写__eq__()方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __hash__(self):
print(self.name, '使用了__hash__方法')
return hash(self.name)
# def __eq__(self, other):
# print(self.name, '使用了__eq__方法')
# return self.__dict__ == other.__dict__
person1 = Person('zs', 20)
person2 = Person('ls', 20)
person3 = Person('ww', 30)
person4 = Person('zs', 20)
set1 = {person1, person2, person3, person4}
print(set1)
不报错,但不符合需求———我们认为person1与person4是同一个人,他们却都被添加到集合,违背了集合的理念:
zs 使用了__hash__方法
ls 使用了__hash__方法
ww 使用了__hash__方法
zs 使用了__hash__方法
{<__main__.Person object at 0x0000000000719CF8>,
<__main__.Person object at 0x00000000007192E8>,
<__main__.Person objec