I am new to programming, and I am trying to learn by making a simple game in pygame. I will be using a lot of clickable buttons, so I decided to make a class for them. As attributes, I want them to have a pygame.Rect object (to tell me where to put them on the screen), a pygame.Surface object (to tell me how it should look like) and a function that I call 'action' in the code below, which will be called whenever the button is clicked. Here is my attempt:
class Button:
def __init__(self, rect, surf, action = None):
self.rect = rect
self.surf = surf
self.action = action
def draw(self, surf):
surf.blit(self.surf, self.rect)
def click(self, event):
if event.type == pygame.MOUSEBUTTONUP:
mouse_pos = pygame.mouse.get_pos()
if self.rect.collidepoint(mouse_pos) and self.action != None:
self.action()
For example, if I want to make a button that increases some global variable "money" by 1, then I can do
def change_money():
global money
money = money + 1
#some code here to define button_rect, button_surf
button = Button(button_rect, button_surf, change_money)
This does the job but it very unsatisfying, because if I wanted to make a new button that increases money by 2, I would have to define a new function change_money_2()
and then do button2 = Button(button2_rect, button2_surf, change_money_2)
I tried the naive approach:
def change_money(delta):
global money
money = money + delta
button2 = Button(button_rect, button_surf, change_money(2))
but this does not work.
Question 1 What is the proper syntax for passing functions as attributes of classes; in particular, what do you do if the function has inputs?
Question 2 Ideally, I would like to not have to define a new function for the simple operation money = money + 1
. Is there a way of passing such a function as an attribute of the class without having to give it a name? (for example, something like button = Button(button_rect, button_surf, [money -> money + 1])
.
Edit 1: Thank you for the suggestion of using lambda functions; I did not know about these. Is there a way of having a lambda function take a global variable? The naive lambda global money : money = money + 2
or lambda : money = money + 2
do not seem to work. My intuition (based on Rabbid76's reference) is that these lambda functions are great for "mimicking" functions with a return statement, but what if I want to mimic a function that has no return statement, like change_money()?
Use a lambda:
button2 = Button(button_rect, button_surf, change_money(2))
button2 = Button(button_rect, button_surf, lambda: change_money(2))
Is there a way of having a lambda function take a global variable?
No, you can't use the global
statement in the lambda expression. The lambda has no statement list, it is a single expression.