【问题标题】:Adding new objects of the same class in a loop在循环中添加同一类的新对象
【发布时间】:2013-01-31 19:02:47
【问题描述】:

我不确定标题是否给出了最好的描述。但这是我的问题。 我有一个名为“球”的课程。 每个球都有自己的宽度、半径和颜色。 当我在循环之前添加自己的球时,我的代码运行良好 例如。球1 = 球() .... 球2 = 球() 我正在使用 pygame,我想要的是,每当我按下“空格”时,它都会添加另一个具有自己特征的球。我有它,所以它随机给出宽度、半径和颜色。 这是我的代码:

BLACK = (0,0,0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)

fps = 30

color_list = [BLACK, BLUE, GREEN, RED]

col = None
siz = None
wit = None
posx = None
posy = None
ball = None


class Ball:

    ballCount = 0

    def __init__(self):
        Ball.ballCount +=1
        self.col = random.choice(color_list)
        self.siz = random.randint(20, 80)
        self.wit = random.randint(1, 3)
        self.posx = random.randint(self.siz, width-self.siz)
        self.posy = random.randint(self.siz, height-self.siz)

    def blitball(self):
        pygame.draw.circle(screen, self.col, (self.posx, self.posy),self.siz, self.wit)


    def move(self):
        self.posx+=1



ball2 = Ball()
ball1 = Ball()
ball3 = Ball()

while True:

    amount = 0



    event = pygame.event.poll()
    keys = pygame.key.get_pressed()

    if event.type == QUIT:
        pygame.quit()
        sys.exit()

    if keys[K_q]:
        pygame.quit()
        sys.exit()

    #############################################################

    if keys[K_SPACE]:
        eval("ball"+str(Ball.ballCount+1)) = Ball()

    #############################################################

    screen.fill(WHITE)

    for r in range(Ball.ballCount):
        amount+=1
        eval("ball"+str(amount)).move()
        eval("ball"+str(amount)).blitball()


    pygame.time.wait(int(1000/fps))

    pygame.display.update()

使用了for r in range(Ball.ballCount):,因此我不必为每个球键入函数。这完美地工作。如果您知道更简单的方法,请告诉我。

所以我需要补充的是:

if keys[K_SPACE]:  
    #add another ball, ball3, ball4,..etc. 

如果这意味着更改我的某些代码,请随时告诉我,甚至自己动手。 感谢您提前回复。 (我在标签中有我的问题)

丹尼斯

【问题讨论】:

  • 您已经使用过列表,因此您应该了解它们。为什么不也使用它们呢?
  • 这里看起来更像是一个设计问题——你试图让 Balls 做两件事——代表一个 Ball 对象,同时跟踪所有其他 ball 对象。如果您将它们作为两个独立的问题处理,您的设计似乎会简单得多;球列表和球本身。

标签: python class object python-3.x pygame


【解决方案1】:

将你的球存储在一个列表中并在那里对它们采取行动

# starting three balls
balls = [Ball(),Ball(),Ball()]

while True:
    amount = 0

    event = pygame.event.poll()
    keys = pygame.key.get_pressed()

    if event.type == QUIT:
        pygame.quit()
        sys.exit()

    if keys[K_q]:
        pygame.quit()
        sys.exit()

    #############################################################

    if keys[K_SPACE]:
        balls.append(Ball())

    #############################################################

    screen.fill(WHITE)

    for ball_in_play in balls:
        ball_in_play.move()
        ball_in_play.blitball()


    pygame.time.wait(int(1000/fps))

    pygame.display.update()

【讨论】:

  • +1 用于显示代码,包括为什么 list 使循环变得更好。
  • 谢谢一百万,从现在开始我会做到这一点的!
【解决方案2】:

您几乎不想按名称创建新变量。

而且,即使在极少数情况下,您也几乎不想使用 evalexec

而且,即使您确实想使用evalexec,您也几乎不想将它们与默认的locals/globals 一起使用。

但是,让我们先看看为什么您的代码不能正常工作,然后再看看如何做得更好。

eval("ball"+str(Ball.ballCount+1)) = Ball()

您正在生成一个类似"ball4" 的字符串,然后在上面调用eval。毫不奇怪,它的计算结果为字符串"ball4"。然后,您尝试将新值(新构造的 Ball 实例)分配给该字符串,而不是变量,显然这不起作用。 (实际上,我猜你会得到一个 SyntaxError 来尝试分配给一个函数调用,甚至在任何事情都被评估之前。)

要解决这个问题,您必须将整个内容放入 eval

eval("ball"+str(Ball.ballCount+1) + " = Ball()")

但这不起作用,因为eval 仅适用于表达式,而不适用于语句。语句需要exec:

exec("ball"+str(Ball.ballCount+1) + " = Ball()")

这将消除你的错误。

但是让我们看看创建ball4 变量的正确方法:

locals()["ball" + str(Ball.ballCount+1)] = Ball()

更简单也更难出错。

但是一旦你看到了,既然你可以使用任何你想要的任何名称的dict,为什么还要麻烦使用locals() 作为dict

my_balls["ball" + str(Ball.ballCount+1)] = Ball()

而且,一旦你这样做了,你就不需要在每一个上都加上“ball”前缀了:

my_balls[Ball.ballCount+1] = Ball()

此时,您可能会意识到您的键只是自然数,这意味着您只是在模拟 listdict,所以您不妨将 my_balls 设为 @987654348 @。

然后,您不再需要 Ball.ballCount — 只需 len(my_balls)

那么,使用evalexec 有什么不好?

嗯,它的效率较低,它使您的代码更难调试(并在交互式终端中进行试验),并且它打开了巨大的安全漏洞(假设您向用户询问下一个球号,他给了您返回 "3; os.system('rm -rf /'); _ " 然后你尝试exec("Ball" + user_input_string + " = Ball()"))。

但与它使您的代码更难阅读这一事实相比,所有这些都算不了什么。比较:

eval("ball"+str(amount)).move()

balls[amount].move()

【讨论】:

  • 非常感谢您的回答。虽然我认为 Paul Seeb 展示了一种出色的方式来完成我想做的事情,但我很高兴现在我对 Eval 和 Exec 的理解有了很多,而且对于我未来的一些程序,这个答案应该对我有很大帮助.我选择了 Paul Seebs 的答案,因为这就是我将在我的代码中使用的答案,但你的答案同样有用,而且这是一个艰难的决定。非常感谢。
猜你喜欢
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
  • 2016-03-17
相关资源
最近更新 更多