[英]Python inventory of objects
我希望能夠對對象實例執行“數學”操作。 假設我有一個Fruit
類,然后再有其他Orange(Fruit)
和Apple(Fruit)
類。
Apple
具有顏色屬性,並且該類意識到“紅色蘋果”與“綠色”或“黃色”蘋果不同。
現在我希望能夠:
1)代表特定水果實例的數量。 例如3個紅蘋果或2個橙子或1個香蕉(是的,可能需要一個新的香蕉類)。
2)代表“水果袋”。 例如1個紅色蘋果和2個橘子。 或1個紅色蘋果和2個橘子
3)按預期在“水果袋”和“水果數量”上運行。 即“ 2個紅色蘋果” +“ 1個紅色蘋果和1個橙子” =>“ 3個紅色蘋果和1個橙子”,甚至還有“ 2個紅色蘋果” * 2 =>“ 4個紅色蘋果”,依此類推。
現在,在某些方面,它看起來與Counter
類的功能類似,但是我不確定應該如何實現它。
我在這里的基本難題是, Counter
類似乎基於兩個對象的哈希值確定兩個對象是否相同,並且基於該相同的哈希值進行分組,並且沒有為我提供選擇“ 3”組鍵的選項紅蘋果”是“紅蘋果”。
我知道如何處理所有數學重載問題,我想我可以從頭開始實現所有這些,但是我希望有其他支持這些概念的現成解決方案。
實際的應用程序當然要復雜得多,但是我認為我在此描述的問題的解決方案很容易擴展到我的實際需求。
您會建議我采用哪種方法? 可以在某些方面使用Counter還是我需要自己完成全部實現?
編輯1:一些更多的想法,我真的很喜歡@ jbndlr關於“您說整數w /值3,而不是3整數”的評論。 但是有區別...
您如何將w /值1的整數,w /值1的整數和w /值4的第三個整數相加? 三個整數會是正確的答案嗎? 還是“ 2個整數w /值為1和1個整數w /值為4?
計數不像求和...
從某種抽象的角度來看,它將使send根據其類型對事物進行計數,這將迫使您在'1 red_apple'+'1 green_apple'只是'1 red_apple + 1 green_apple'(因為green_apple和red_apple有所不同),而'1紅色的蘋果'+'1綠色的蘋果'可以看作是'2個蘋果'(因為一個蘋果)任何其他顏色都會像蘋果一樣)
問題是,如果您的應用程序域要求按顏色對蘋果進行分組,那么您仍然不想強迫創建3種不同類別的蘋果,而只想按顏色區分蘋果實例。
可能這是我走錯了路,而決定計數方式的正確方法是進行實際計數,這樣您就可以提供哈希方案作為對某些CounterFactory函數的調用的一部分將返回一個Counter,該Counter知道對於提供的某種類型的對象實例,他的期望是什么。
另一種選擇是假設每種類型只能以某種特定方式計數,並且由類決定什么是對其實例進行計數的正確方法,並因此提供類似__counting_key__這樣的東西來支持向后兼容的方式來控制Counter類的行為。
感謝所有出色的回答,我當然有足夠的能力去與之合作。 我將接受似乎最接近最終我最終選擇的解決方案的解決方案。
實際上,您可以非常輕松地設置自己的類。 我認為,如果只想允許對新類型(此處為類)進行常規算術運算,那么重用Counter
任何東西(甚至使用新types
擴展python)都將花費很多精力。
本示例概述了如何實現比較器和運算符重載。 在此示例腳本的結尾查看如何使用這些類:
class FruitKind(object):
def __init__(self, count=1):
self.count = count
class Apple(FruitKind):
def __init__(self, color, count=1):
super(Apple, self).__init__(count)
if isinstance(color, basestring):
self.color = color
else:
raise TypeError('Color must be string-like.')
def __str__(self):
return '{} {} Apple(s)'.format(self.count, self.color)
def __eq__(self, other):
if all([
type(self) is type(other),
self.color == other.color
]):
return True
return False
def __ne__(self, other):
return not self.__eq__(other)
def __add__(self, other):
if self == other:
self.count += other.count
return self
else:
raise TypeError('Cannot add different Fruits.')
def __sub__(self, other):
if self == other:
self.count += other.count
return self
else:
raise TypeError('Cannot subtract different Fruits.')
class FruitBag(object):
def __init__(self, items=[]):
self.items = items
def __add__(self, other):
if isinstance(other, FruitBag):
# Merge self.items and other.items
pass
elif isinstance(other, FruitKind):
# Merge other into self.items
pass
else:
raise NotImplementedError(
'Cannot add instance of {} to Fruitbag.'
.format(str(type(other))))
if __name__ == '__main__':
a1 = Apple('red')
a2 = Apple('red', count=3)
a1 += a2
print(a1)
a3 = Apple('green')
try:
a1 += a3
except TypeError as te:
print(te.message)
運行此命令將產生以下輸出:
4 red Apple(s)
Cannot add different Fruits.
但是,在此示例中,我將FruitKind
視為對水果的描述以及使其在其他水果中獨一無二的屬性(兩個蘋果可能是兩個蘋果,但是在這里,顏色也用於區分它們)。 結果,從FruitKind
繼承的類(例如Apple
)始終也攜帶許多項目。
您可以覆蓋對象的__hash__(self)
,以便根據要隔離的屬性進行計算; 您還可以覆蓋__eq__
方法和其他比較器方法。
例如:
class Apple(Fruit):
def __init__(self, ...):
self.color = 'red' # maybe create an Enum for the colors?
def __hash__(self):
return hash(('apple', self.color)) # Thanks @Jon Clements in the comments
def __eq__(self, other): # recommended when overwriting __hash__ - thanks @Jon Clements
return True if self equals other, False otherwise
您可能需要考慮使散列更通用...可以使用self.__class__.__name__
或其他self.__class__.__name__
(來自@Jon Clements注釋)
class FruitBasket:
def __init__(self):
self.fruits = []
def add_fruit(self, fruit):
self.fruit.append(fruit)
def __iter__(self):
return iterable over self.fruits
counter = Counter(FruitBasket)
這是喬恩·克萊門茨(Jon Clements)在此處發布的要點:
我將他的答案發布為社區Wiki答案。
class Fruit:
def __init__(self, colour):
self.colour = colour
def __hash__(self):
return hash((self.__class__.__name__, self.colour))
def __eq__(self, other):
return type(self) == type(other) and self.colour == other.colour
def __repr__(self):
return '{} ({})'.format(self.__class__.__name__, self.colour)
class Apple(Fruit):
pass
class Berry(Fruit):
pass
from collections import Counter
fruits = [
Apple('red'), Apple('green'), Berry('black'), Berry('red'),
Berry('black'), Apple('red'), Berry('red'), Apple('green'),
Berry('blue'), Apple('pink')
]
counts = Counter(fruits)
#Counter({Apple (green): 2,
# Apple (pink): 1,
# Apple (red): 2,
# Berry (black): 2,
# Berry (blue): 1,
# Berry (red): 2})
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.