恩… 我重新改寫一下這篇
因為在我發文的後幾天我解決了,且在前輩的幫助下我有了更新一層的領悟
我有點不知道這篇的知識該擺在哪,小筆記當初規劃是開來存放每次解決的小問題
今天介紹 __eq__, __hash__
在Python 物件Object的做法
起初是因為一連串重複的object list中取除獨特的物件list
若set() 使用在數值上,是可以直接去除重複值的
>>> list = [2,3,4,5,5,5,5,2,2,3,4,5]
>>> list
[2, 3, 4, 5, 5, 5, 5, 2, 2, 3, 4, 5]
>>> set(list)
{2, 3, 4, 5}
所以代表set利用在數字上是可以去除重複值
假設我的物件List長這樣
o_list = [data, data, data, data, data, data]
其中只會有3個物件是獨立的,但利用set()去實作並沒有篩選出獨立的3個物件
我先後參考這些文件撰寫出程式碼
How to remove duplicates in set for objects?
以及許多
然後造樣寫了一個這個
class RemoveDuplicate(object):
def __init__(self, data):
self.data = data.data
self.id = data.id
self.column = data.column_name
self.table = data.table_name
def __eq__(self, other):
return (self.id) == (other.id)
def __hash__(self):
return hash(self.id)
data_set = set()
for data, book in library:
for each_data in list(data):
data_list.add(RemoveDuplicate(each_data))
最後比較折騰我的原因是因為我的程式實際上傳的data 資料是 Object 裡又包Object
而且剛好內部的object 是unhashable
我的data簡單來說長這樣
data
id = 1
object(OrderedDict)
column = "..."
table = "..."
在我的data中有包了一個object 是 OrderedDict,他是不可被hash
來介紹一下此篇 Object, Equal, Hash
Equal 這個功能,前輩說在各大程式語言內都看得到,例如JAVA openhome.cc ,CodeData
例如C #
前輩丟了這篇給我讓我捉模一下 Python Hashes and Equality
Equal 在這寫是檢查兩個物件有沒有相同
而相同的依據就是 __eq__
去定義
def __eq__(self, other):
return (self.id) == (other.id)
在我的程式碼內是使用data.id 若相同就是同個物件
什麼Hash? 雜湊函式
講一個例子就是有一副樸克牌,Hash的元件為紅心,黑桃,方塊及梅花
接下來塞52張不同花色的牌卡下去後,經過Hash,樸克牌會像牌七一樣,同樣花色的排一排,該是紅心的牌他就會排在紅心的List後
紅心, [紅心Q, 紅心3, 紅心1, ...]
黑桃, [黑桃1, 黑桃K, 黑桃2,...]
Hash 算是將物件中的某幾個元件(自己定)建立為固定的指紋, 若資料符合一系列的指紋就會被識別出來
而且可被Hash(Hashable)的元件要是不可變動(Immutable),這樣才能拿來作eq比較
# 我用id 當hash
def __hash__(self):
return hash(self.id)
所以__eq__ + hash ,就是hash會篩選出不同的桶子,而eq則會去比對說不同桶子內若其中有什麼元件是相同的,就會判定兩個桶子(物件)是一樣的
根據Python2.7文章中,
要使用Set做eq比較,唯有被hash過的物件才會被放進eq比較
若Class Object沒有__eq__()
的話,那就不用__hash__()
可是如果有使用__eq__()
,就一定要用__hash__()
意思是寫了eq, 就要用hash,而set會自動呼叫__hash__()
來看一下Python 3與 2的文件 set 3.6 及 set 2.7
set 內的元件必須要可被Hash
The elements of a set must be <span class="xref std std-term">hashable</span>.
set不能包含可變動的元件,像是list或字典。
但他可包含不可變動的群組,像是tuple
As a result, <strong>sets cannot contain mutable elements</strong> such as lists or dictionaries.
However, they <strong>can contain immutable collections</strong> such as tuples or instances of<code class="xref py py-class docutils literal notranslate"><span class="pre">ImmutableSet</span></code>.
甚麼是Mutable/ Immutable?
我找了一篇文章
Mutable vs Immutable Objects in Python
裡面提及
**Mutable objects(我就翻為可變動物件)**:
list, dict, set, byte array
**Immutable objects(不可變動):**
int, float, complex, string, tuple, frozen set [note: immutable version of set], bytes
要使用Set 及 __eq__和 hash
首先確定eq的條件,接著
只有被hash的元件才會拿來做比較
set 會自動執行hash, 若沒有hash函式就不會進到eq
只有可被hash(不可變動的元件Immutable),才可做為eq 做比對
至於如果遇到字典, 串列,或者像我的例子中OrderedDict’,真的要對這些變動元件做hash怎麼辦呢?
在我的data 物件中,包含了OrderedDict, 而OrderedDict,屬於Dictionary的一種
Dictionary 是 Mutable objects, 不可被hash
Python unhashable type: ‘OrderedDict’
In your case, var1
contains some object that is not hashable (it does not implement hash()
).
This object is an OrderedDict
, which is a mutable object and is not hashable by design.
對於unhashable的物件,你可使用
frozenset() 回傳
以下是我的程式碼
class RemoveDuplicate(object):
def __init__(self, data):
<strong>self.data = data.data</strong>
self.id = data.id
self.column = data.column_name
self.table = data.table_name
def __eq__(self, other):
return (self.id) == (other.id)
def __hash__(self):
return hash((self.id, <strong>frozenset(self.data)</strong>, self.table, self.column))
data_set = set()
for data, book in library:
for each_data in list(data):
data_list.add(RemoveDuplicate(each_data))
粗字是OrderedDict 物件,可以使用這樣的方法來Hash
參考文章, 此篇可以解決dict unhashable