本章介紹一下python類中的一些內(nèi)置方法。內(nèi)置的方法有很多,有些內(nèi)置方法在object類中已經(jīng)定義,子類可以拿來直接使用,也可以重寫,但是有些內(nèi)置方法object類中沒有,比如 __len__ 方法(len()方法會調(diào)用 對應(yīng)類中的 __len__ 方法),需要根據(jù)需求來進行定義~
創(chuàng)新互聯(lián)建站專注于西秀企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站設(shè)計,電子商務(wù)商城網(wǎng)站建設(shè)。西秀網(wǎng)站建設(shè)公司,為西秀等地區(qū)提供建站服務(wù)。全流程按需開發(fā),專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)建站專業(yè)和態(tài)度為您提供的服務(wù)
對象的字符串顯示 會調(diào)用__str__ 或 __repr__ 方法,__str__ 和 __repr__ 方法在object中已經(jīng)定義,默認(rèn)都是輸出對象在內(nèi)存中的地址,有時候根據(jù)需求需要重寫這兩個方法~
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
def __repr__(self):
return '(%s,%s)' % (self.name, self.city)
def __str__(self):
return '(%s,%s)' % (self.name, self.age)
p = Person('Kitty', 19, 'HZ')
print(p) # (Kitty,19),調(diào)用 __str__
print(str(p)) # (Kitty,19),調(diào)用 __str__
print(repr(p)) # (Kitty,HZ),調(diào)用 __repr__
print('%s' % p) # (Kitty,19),調(diào)用 __str__
print('%r' % p) # (Kitty,HZ),調(diào)用 __repr__
在交互式解釋其中,直接輸出對象,會調(diào)用 __repr__ 方法
>>> p = Person('Kitty', 19, 'HZ')
>>> p
(Kitty,HZ)
Tip:
用于將對象格式化輸出
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
def __format__(self, format_spec):
fmt = {
'-': '{obj.name}-{obj.age}-{obj.city}',
'/': '{obj.name}/{obj.age}/{obj.city}'
}[format_spec]
return fmt.format(obj = self)
p = Person('Kitty', 19, 'HZ')
# format 函數(shù)會調(diào)用對象的綁定方法 __format__
print(format(p, '-'))
print(format(p, '/'))
# 輸出結(jié)果:
Kitty-19-HZ
Kitty/19/HZ
析構(gòu)方法,當(dāng)對象在內(nèi)存中被釋放時,會自動觸發(fā)執(zhí)行。但是此方法一般無須定義,因為Python解釋器會來完成內(nèi)存的分配和釋放工作,所以,析構(gòu)方法的調(diào)用是由解釋器在進行垃圾回收時自動觸發(fā)執(zhí)行的。
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
def __del__(self):
print('delete...')
p = Person('Kitty', 19, 'HZ')
del p
# 輸出結(jié)果:
delete...
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, item):
self.__dict__.pop(item)
def __delattr__(self, key):
self.__dict__.pop(key)
p = Person('Kitty', 19)
print(p['name']) # Kitty,調(diào)用 __getitem__ 方法
p['age'] = 18
print(p['age']) # 18
p['city'] = 'HZ'
print(p.__dict__) # 調(diào)用 __setitem__ 方法
# {'name': 'Kitty', 'age': 18, 'city': 'HZ'}
del p['city'] # 調(diào)用 __delitem__ 方法
print(p.__dict__)
# {'name': 'Kitty', 'age': 18}
del p.age # 調(diào)用 __delattr__ 方法
print(p.__dict__)
# {'name': 'Kitty'}
len(obj) 會調(diào)用obj的 __len__ 方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __len__(self):
return len(self.__dict__)
p = Person('Kitty', 19)
print(len(p)) # 2
對象后面加括號,就會觸發(fā) __call__ 方法的執(zhí)行,即調(diào)用方式:對象() 或者 類()()
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def __call__(self):
print('hello' + ' ' + self.__name)
p = Person('Kitty', 19)() # hello Kitty
# p()
在類的是實例化過程中,第一個被調(diào)用的是 __new__方法。在對象的初始化之前首先要創(chuàng)建對象,__new__方法正是用來創(chuàng)建這個對象~
?;
類的實例化過程也可以通過如下語句來實現(xiàn):
>>> p = object.__new__(Person)
>>> Person.__init__(p, 'Kitty', 18)
>>> p.name
'Kitty'
在Person類中重寫 __new__方法:
class Person:
country = "China"
def __new__(cls, name, age):
print('__new__ called')
return super(Person, cls).__new__(cls)
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self, word):
print(word)
p = Person('Kitty', 18) # 實例化對象
print('name : %s' % p.name)
# 輸出結(jié)果:
__new__ called
name : Kitty
可以看到 __new__ 方法 是先于 __init__ 方法被調(diào)用的~
類的實例化過程大致步驟如下:
1、p = Person('Kitty', 18) ,會調(diào)用 Person類的 __new__ 方法,并傳遞 name 和 age 參數(shù)
2、__new__ 方法 會創(chuàng)建一個 Person類的對象并返回
3、最后利用這個對象調(diào)用類的 __init__ 方法 完成初始化,__init__ 方法的第一個參數(shù)是self,對象在調(diào)用 __init__ 方法時會將自己當(dāng)做參數(shù)傳遞給 這個self。
重寫 __new__ 來實現(xiàn)單例模式~
class Person:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Person, cls).__new__(cls, *args, **kwargs)
return cls._instance
p1 = Person()
p2 = Person()
print(p1) # <__main__.Person object at 0x108eb6438>
print(p2) # <__main__.Person object at 0x108eb6438>
對象的內(nèi)存地址相同,則表示為同一個對象~
在判斷兩個對象是否一致時,往往會用到這兩個函數(shù)~
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def __hash__(self):
return hash(str(self.__name))
p = Person('Kitty', '19')
print(hash(p))
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, obj):
if self.name == obj.name and self.age == obj.age:
return True
p1 = Person('Kitty', '19')
p2 = Person('Kitty', '19')
print(p1 == p2) # True
?
集合(set)是一個無序不重復(fù)元素的序列。集合中只能存放不可變對象(可hash的)。在向 set 集合中添加對象時,會通過調(diào)用對象的 __hash__ 和 __eq__ 這兩個方法來判斷集合中是否已經(jīng)存在一樣的對象~
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __hash__(self):
print('調(diào)用了__hash__方法')
return hash(self.name)
def __eq__(self, obj):
print('調(diào)用了__eq__方法')
return self.name == obj.name and self.age == obj.age
def __str__(self):
return '(' + self.name + ', ' + self.age + ')'
p1 = Person('Tom', '19') # 調(diào)用了__hash__方法
p2 = Person('Jeff', '20') # 調(diào)用了__hash__方法
my_set = {p1, p2}
for i in my_set:
print(i) # (Jeff, 20), (Tom, 19)
在向 set 集合中添加對象時,會首先調(diào)用對象的 __hash__ 若是 返回的 hash值不一樣,則認(rèn)為不是重復(fù)的對象,進行添加~
p1 = Person('Tom', '19') # 調(diào)用了__hash__方法
p2 = Person('Tom', '20') # 調(diào)用了__hash__方法,調(diào)用了__eq__方法
my_set = {p1, p2}
for i in my_set: # (Tom, 20), (Tom, 19)
print(i)
若是返回的hash值有重復(fù)的,則會接著調(diào)用對象 __eq__ 方法,若 __eq__ 方法的返回值為False,則認(rèn)為不是重復(fù)對象,進行添加,若返回為True,則不進行添加~
?
所以總結(jié)一下:set結(jié)合的去重是通過調(diào)用對象的 __hash__ 和 __eq__ 這兩個方法共同實現(xiàn)的
1、首先調(diào)用對象的 __hash__方法,返回的hash值不存在重復(fù),則直接添加該對象;
2、當(dāng)返回的hash值存在重復(fù),接著再調(diào)用 __eq__ 方法,返回為False,添加對象,返回為True,不進行添加~
.................^_^