本章介紹一下python類中的一些內置方法。內置的方法有不少,有些內置方法在object類中已經定義,子類能夠拿來直接使用,也能夠重寫,可是有些內置方法object類中沒有,好比 __len__ 方法(len()方法會調用 對應類中的 __len__ 方法),須要根據需求來進行定義~python
對象的字符串顯示 會調用__str__ 或 __repr__ 方法,__str__ 和 __repr__ 方法在object中已經定義,默認都是輸出對象在內存中的地址,有時候根據需求須要重寫這兩個方法~ide
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),調用 __str__ print(str(p)) # (Kitty,19),調用 __str__ print(repr(p)) # (Kitty,HZ),調用 __repr__ print('%s' % p) # (Kitty,19),調用 __str__ print('%r' % p) # (Kitty,HZ),調用 __repr__
在交互式解釋其中,直接輸出對象,會調用 __repr__ 方法函數
>>> p = Person('Kitty', 19, 'HZ') >>> p (Kitty,HZ)
Tip:code
用於將對象格式化輸出orm
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 函數會調用對象的綁定方法 __format__ print(format(p, '-')) print(format(p, '/')) # 輸出結果: Kitty-19-HZ Kitty/19/HZ
析構方法,當對象在內存中被釋放時,會自動觸發執行。可是此方法通常無須定義,由於Python解釋器會來完成內存的分配和釋放工做,因此,析構方法的調用是由解釋器在進行垃圾回收時自動觸發執行的。對象
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 # 輸出結果: 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,調用 __getitem__ 方法 p['age'] = 18 print(p['age']) # 18 p['city'] = 'HZ' print(p.__dict__) # 調用 __setitem__ 方法 # {'name': 'Kitty', 'age': 18, 'city': 'HZ'} del p['city'] # 調用 __delitem__ 方法 print(p.__dict__) # {'name': 'Kitty', 'age': 18} del p.age # 調用 __delattr__ 方法 print(p.__dict__) # {'name': 'Kitty'}
len(obj) 會調用obj的 __len__ 方法ip
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
對象後面加括號,就會觸發 __call__ 方法的執行,即調用方式:對象() 或者 類()()內存
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()
在類的是實例化過程當中,第一個被調用的是 __new__方法。在對象的初始化以前首先要建立對象,__new__方法正是用來建立這個對象~
;
類的實例化過程也能夠經過以下語句來實現:ci
>>> 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) # 輸出結果: __new__ called name : Kitty
能夠看到 __new__ 方法 是先於 __init__ 方法被調用的~
類的實例化過程大體步驟以下:
一、p = Person('Kitty', 18) ,會調用 Person類的 __new__ 方法,並傳遞 name 和 age 參數
二、__new__ 方法 會建立一個 Person類的對象並返回
三、最後利用這個對象調用類的 __init__ 方法 完成初始化,__init__ 方法的第一個參數是self,對象在調用 __init__ 方法時會將本身當作參數傳遞給 這個self。
重寫 __new__ 來實現單例模式~
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>
對象的內存地址相同,則表示爲同一個對象~
在判斷兩個對象是否一致時,每每會用到這兩個函數~
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)是一個無序不重複元素的序列。集合中只能存放不可變對象(可hash的)。在向 set 集合中添加對象時,會經過調用對象的 __hash__ 和 __eq__ 這兩個方法來判斷集合中是否已經存在同樣的對象~
class Person: def __init__(self, name, age): self.name = name self.age = age def __hash__(self): print('調用了__hash__方法') return hash(self.name) def __eq__(self, obj): print('調用了__eq__方法') return self.name == obj.name and self.age == obj.age def __str__(self): return '(' + self.name + ', ' + self.age + ')' p1 = Person('Tom', '19') # 調用了__hash__方法 p2 = Person('Jeff', '20') # 調用了__hash__方法 my_set = {p1, p2} for i in my_set: print(i) # (Jeff, 20), (Tom, 19)
在向 set 集合中添加對象時,會首先調用對象的 __hash__ 如果 返回的 hash值不同,則認爲不是重複的對象,進行添加~
p1 = Person('Tom', '19') # 調用了__hash__方法 p2 = Person('Tom', '20') # 調用了__hash__方法,調用了__eq__方法 my_set = {p1, p2} for i in my_set: # (Tom, 20), (Tom, 19) print(i)
如果返回的hash值有重複的,則會接着調用對象 __eq__ 方法,若 __eq__ 方法的返回值爲False,則認爲不是重複對象,進行添加,若返回爲True,則不進行添加~
因此總結一下:set結合的去重是經過調用對象的 __hash__ 和 __eq__ 這兩個方法共同實現的
一、首先調用對象的 __hash__方法,返回的hash值不存在重複,則直接添加該對象;
二、當返回的hash值存在重複,接着再調用 __eq__ 方法,返回爲False,添加對象,返回爲True,不進行添加~
.................^_^