3

我想构造一个具有特殊行为的对象,并且我很确定它可以用 python 完成(使用生成器,或某种棘手的类定义)。

我基本上想要一个对象——我们称之为它—— colourgun,每次我访问它时,它都会从预定义的颜色列表中返回一种颜色。所以它的行为应该像一个简单的变量,但每次访问它时都会改变它的行为。

您可以在以下示例中看到一些类似的概念:

class CounterList(list):
    def __init__(self, *args):
        super(CounterList, self).__init__(*args)
        self.counter = 0
    def __getitem__(self, index):
        self.counter += 1
        return super(CounterList, self).__getitem__(index)

每次访问列表时都会CounterList增加一个实例,因为被调用。counter__getitem__

colourgun应该能够检测到它何时“使用”并表现如下:

>>> gun = Colourgun() # or a function, a generator, whatever...
>>> print gun
'predefined_colour1'
>>> print gun
'predefined_colour2'
>>> print gun
'predefined_colour3'
>>> print gun # no more colours left: reloading and maybe warn the user
[WARNING] automatically reloading the gun
'predefined_colour1'
>>> gun.load(['colour1', 'colour2', 'colour3']) # some way to load it with colours
>>> print gun
'colour1'
>>> print gun
'colour2'
>>> gun.reload() # manually reloading
>>> print gun
'colour1'

关键是,我不想在每次访问变量时显式调用“拍摄颜色”的方法。我想这表明变量确实应该是一个函数或一个生成器(至少可以冻结它的状态)。

我做了一些实验,这是一种更接近这个想法的尝试,但它不起作用,因为我将 Shoot() 的返回值而不是函数本身绑定到变量gun

class ColourGun(object) :
    def __init__(self) :
        self.colours = ['predefined_colour1', 'predefined_colour2', 'predefined_colour3']
        self.counter = 0
    def Shoot(self) :
        c = self.colours[self.counter]
        self.counter += 1
        return c

gun = ColorGun().Shoot()

print gun
print gun
print gun

哪个当然会打印predefined_colour1三遍……</p>

所以肯定有一个基于生成器或类和生成器的组合或其他东西的概念,它可以以pythonic的方式来实现。(或者也许是一种设计模式?)

PS:如果您有更好的标题的想法,请告诉我,并随时添加更多标签……</p>

更新

所以用属性来做(正如wim建议的那样):

class ColorGun(object) :
    def __init__(self) :
        self.colours = ['predefined_colour1', 'predefined_colour2', 'predefined_colour3']
        self.counter = 0
    @property
    def Shoot(self) :
        if self.counter >= len(self.colours) :
            self.counter = 0
            print "automatically reloading"
        c = self.colours[self.counter]
        self.counter += 1
        return c

gun = ColorGun()

print gun.Shoot
print gun.Shoot
print gun.Shoot
print gun.Shoot

这给出了输出:

predefined_colour1
predefined_colour2
predefined_colour3
automatically reloading
predefined_colour1

实现一个reload方法是没有问题的,但我能以某种方式摆脱它.,所以我可以称之为gun而不是gun.Shoot?;-)

4

3 回答 3

5

Something like this...?

import itertools as it

class ColourGun(object):

    def __init__(self):
        self._colourgen = it.cycle(['predefined_colour1', 'predefined_colour2', 'predefined_colour3'])

    def load(self, colours):
        self._colourgen = it.cycle(colours)

    @property
    def colour(self):
        return next(self._colourgen)

    def __str__(self):
      return self.colour

gun = ColourGun()
print gun
print gun
print gun
gun.load(['potato', 'spam', 'eggs'])
print gun
print gun
于 2013-05-08T10:00:54.173 回答
2

Since your being used means print gun, let's just customize the __str__ method.

class ColorGun:

    def __init__(self):
        self.colors = ['red', 'pink']
        self.i = 0

    def __str__(self):
        if not self.colors:
            return

        if self.i >= len(self.colors):
            print '[WARNING] automatically reloading the gun.'
            self.reload()

        c = self.colors[self.i]
        self.i += 1

        return c

    def reload(self, colors=None):
        if colors:
            self.colors = colors
        self.i = 0

gun = ColorGun()
print gun
print gun
print gun
于 2013-05-08T10:00:55.203 回答
1

您可能希望自定义__str__功能以实现该目的。这里举一个简单的例子。

这个例子显示了项目mylist(你可以有一个生成器),当它用尽时,它会打印一个默认值。

class Gun():
    mylist=[1,2,3]
    index=-1
    default='Default'
    def __str__(self):
        try:
            self.index+=1
            return str(self.mylist[self.index])
        except IndexError:
            return self.default


>>> gun=Gun()
>>> print gun
1
>>> print gun
2
>>> print gun
3
>>> print gun
Default
>>> 
于 2013-05-08T10:02:49.677 回答