繁体   English   中英

Python对象清单

[英]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注释)

编辑-与Counter()一起使用:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM