2

我已经开始迈出学习 python 的第一步,并且正在尝试开始使用类。

到目前为止,我有这个简化版本:

class ThingsInTheFridge(object):
  def __init__(self):
    self.milk = False
    self.yogurt = False
    self.bread = True
    self.umbrella = True

我班上大约有 30 件事情,每件事情都被分配了对或错(我已经缩短了这个问题的清单)。

分配它们的最有效方法是什么?

我已经考虑过这一点,但它似乎并没有改善,尤其是当列表大小增加时:

self.milk, self.yogurt = False, False

编辑:我也许应该提到课堂上还有其他项目(我省略了它们,因为我认为这无关紧要):

class ThingsInTheFridge(object):
  def __init__(self):
    self.milk = False
    self.yogurt = False
    self.bread = True
    self.umbrella = True
    self.bulb = "maker name"
    self.shoes = 2
4

4 回答 4

4

如果您真的关心运行时效率,那么您几乎肯定是找错地方了。如果初始化您的成员需要太长时间(这不太可能……但如果您配置文件并发现这是热点……),正确的答案是使用__slots__,而不是改变您进行初始化的方式。

如果您关心程序员的效率(可读性,以及较小程度的可写性),您总是可以这样做:

self.milk = self.yogurt = False

如果你想更动态地做事情,你可以用 做这样的事情setattr,但我不推荐它:

class ThingsInTheFridge(object):
    false_things = ('bread', 'umbrella')
    true_things = ('milk', 'yogurt')
    def __init__(self):
        for thing in ThingsInTheFridge.false_things:
            setattr(self, thing, False)
        for thing in ThingsInTheFridge.true_things:
            setattr(self, thing, True)

我不推荐它的原因是,如果你需要在这个级别动态地做事,你可能还需要在访问级别是动态的,这意味着你真的应该使用dictor set,正如 Lattyware 所解释的那样。

您也可以在类风格系统之上构建自己的原型风格 OO 系统,或者创建一个基于类信息初始化实例的元类等,但是,正如这句话的开头所表明的那样,这将太过分了。

于 2013-02-04T19:30:38.743 回答
4

我认为这表明您的数据存储模型存在问题。您可能希望使用像集合这样的数据结构,而不仅仅是属性。

例如:

items = {"milk", "yogurt", "bread", "umbrella"}
stored = set()

然后只需将您想要的存储在stored集合中。集合在成员检查方面具有非常快的性能,所以要检查,你可以简单地做"milk" in stored,例如。

如果您真的想保留您拥有的界面,您可以使用__getattr__()覆盖您在请求属性时获得的操作:

def ___getattr__(self, item):
    return item in self.stored

这将返回False到冰箱里没有的任何东西,如果你需要它只响应可能的物品,这很容易做到:

def ___getattr__(self, item):
    if item not in self.items:
        raise AttributeError
    return item in self.stored

当然,也可以进行设置:

def __setattr__(self, item, value):
    if item in self.items:
        if value:
            self.stored.add(item)
        else:
            self.stored.remove(item)
    else:
        ...

对此的替代方法是True/ False- 我真的不能说我认为任何一个都特别好,一个可能更适合您的项目。只需使用最适合您的东西。

于 2013-02-04T19:31:18.460 回答
1

我认为您的主要关注点应该是可读性和底层数据结构。

像这样的东西是非常易读的,并且(可能)通过滚动你自己可以达到的高性能:

from collections import Counter

class Fridge(object):
    def __init__(self,things,name):
        self.things=Counter(things)
        self.wanted=set()
        self.name=name

    def look(self, thing):
        print 'There are {} {} in {}'.format(self.things[thing],thing,self.name)

    def stare_inside(self):
        cathave=sorted([(co,it) for it,co in self.things.items() if co])
        print '{} items in {}:'.format(len(cathave),self.name)
        for i, item in enumerate(cathave,1):
            print '   {}: {} -- {}'.format(i,item[1],item[0])

    def shop(self):
        shop_list=[it for it,co in self.things.items() if co==0]
        for item in shop_list:
            del self.things[item]
        shop_list.extend(list(self.wanted))
        self.wanted=set()
        print "shopping list:"
        for i, item in enumerate(sorted(shop_list),1):
            print '   {}: {}'.format(i,item)    

    def consume(self,thing,count):
        if self.things[thing]>=count:
            self.things[thing]-=count   
        else: 
            print 'Not enough {} to consume {} -- {} in the {}.'.format(
                  thing,count,self.things[thing],self.name)
            self.wanted.add(thing)

    def stock(self,things):
        self.things+=Counter(things)

现在试试:

>>> kitchen=Fridge({'coke':2, 'whole milk':1,'ketchup':1, 'anchovies':24},'kitchen fridge')
>>> kitchen.look('coke')
There are 2 coke in kitchen fridge
>>> kitchen.stock({'coke':1,'pepsi':2,'banana':3})
>>> kitchen.stare_inside()
6 items in kitchen fridge:
   1: ketchup -- 1
   2: whole milk -- 1
   3: pepsi -- 2
   4: banana -- 3
   5: coke -- 3
   6: anchovies -- 24
>>> kitchen.consume('red bull',22)
Not enough red bull to consume 22 -- 0 in the kitchen fridge.
>>> kitchen.consume('coke',3)
>>> kitchen.consume('whole milk',1)
>>> kitchen.stare_inside()
4 items in kitchen fridge:
   1: ketchup -- 1
   2: pepsi -- 2
   3: banana -- 3
   4: anchovies -- 24
>>> kitchen.shop()
shopping list:
   1: coke
   2: red bull
   3: whole milk

这是基于集合模块 Counter 类。你不太可能想出更快的原生 Python。

于 2013-02-04T20:12:15.633 回答
0

实际上,使用一组字符串而不是单个标志成员可能会更好。对于您似乎正在尝试做的事情,以下内容可能会更好。

class ThingsInTheFridge:
    """I represent a collection of items in a refrigerator.

    I contain a few things by default.  You can add and remove items as
    well as test for membership.

    >>> things = ThingsInTheFridge()
    >>> object() in things
    False
    >>> things.store_item('foo')
    >>> 'foo' in things
    True
    """
    def __init__(self):
        self._items = set()
        self.store_item('bread')
        self.store_item('umbrella')
    def store_item(self, item):
        """Add an item to the fridge.
        :param item: the item to add.

        Items are coerced into strings and normalized before they are
        added to the internal list.

        >>> things = ThingsInTheFridge()
        >>> things.store_item(False)
        >>> 'false' in things
        True
        >>> 'FALSE' in things
        True
        >>> False in things
        True
        """
        self._items.add(str(item).lower())
    def __contains__(self, item):
        """Check if an item is in the fridge.
        :param item: item to check for.

        Items are coerced into strings and normalized to match the processing
        in :py:meth:`store_item`.

        >>> things = ThingsInTheFridge()
        >>> things.store_item('Milk')
        >>> 'Milk' in things, 'milk' in things, 'MiLk' in things
        (True, True, True)
        """
        return str(item).lower() in self._items
于 2013-02-04T19:56:29.960 回答