Mic wrote:

> 
>> >from functools import partial
> 
>>I use this  kind of explicit import for a few names that I use frequently,
>>namely defaultdict, contextmanager, everything from itertools...
>>I think of these as my personal extended set of builtins ;)
> 
>>As to the actual partial() function, you probably don't see it a lot
>>because
>>it has been in the standard library for only three years. The older idiom
>>for making a function that calls another function with a fixed argument is
> 
> command = lambda button=button: button_clicked(button)
> 
> Alright! What is a fixed argument?

Suppose you have a function add() that calculates the sum of two values

>>> def add(a, b):
...     return a + b
...
>>> add(1, 2)
3

If you want another function that takes one argument and adds 2 to that 
argument you can either start from scratch

>>> def plus_two(b):
...     return 2 + b
...
>>> plus_two(7)
9

or build on your earlier work

>>> from functools import partial
>>> plus_two = partial(add, 2)
>>> plus_two(3)
5

The effect of wrapping add into partial here is that every time you call 
plus_two(x) it will in turn call add(2, x). As the first argument is always 
the same I called it "fixed", but it's not a terminus technicus.

>>You can iterate over (row, column) pairs instead of the dummy _ variable:
> 
>>def create_widgets(self):
>     >for row, column in [(0, 0), (1, 1), (2, 2), (3, 0)]:
>         >button = tk.Button(self)
>         >command = partial(button_clicked, button)
>         >button["command"] = command
>         >button.grid(row=row, column=column)
>         >command()
> 
> Very nice! I didn't know that it was possible. This saves me a lot of
> space. Am I, as a beginner, supposed to know this?

You may read it up somewhere or be shown on a mailinglist ;)

> Say that when button one is pressed I want a text file to be created. The
> text in the
> file should be the same number as the button I pressed. So if I press
> button one, once,
> it should create a text file with the name button_1. The text in the file
> should also be "button_1".
> 
> If the button is pressed again, it should remove the file. Is this
> possible to do without
> any trouble?
> 
> So if the second button is pressed , it should create a text file with the
> name button_2
> and the text in it should be button_2. If the button is pressed once
> again, it is supposed to
> delete that file it created.

> I also have one last question.
> How do I make the first button that is created to be named
> 1, the second to be created 2, the third 3 and so on?

Here's a modified script:

import tkinter as tk
from functools import partial

def button_clicked(button):
    if button["bg"] == "green":
        button["bg"] = "red"
        print("deleting file", button.filename)
    else:
        button["bg"] = "green"
        print("creating file", button.filename)

class Window(tk.Frame):
    def __init__(self, master):
        super (Window, self).__init__(master)
        self.grid()
        self.create_widgets()

    def create_widgets(self):
        for index in range(20):
            button = tk.Button(self, text="Button {}".format(index+1), 
bg="red")
            button.filename = "button{}.txt".format(index+1)
            command = partial(button_clicked, button)
            button["command"] = command
            row, column = divmod(index, 4)
            button.grid(row=row, column=column)

root = tk.Tk()
root.title("Test")
app = Window(root)
root.mainloop()

I hope you can infer answers to your questions from the above...

To be honest, we've reached the point where I would switch to a 
tkinter.Button subclass:

import tkinter as tk

FREE = "green"
OCCUPIED = "red"

class SeatButton(tk.Button):
    def __init__(self, master, index):
        text = "Button {}".format(index+1)
        super(SeatButton, self).__init__(master, text=text, bg=FREE, 
command=self.clicked)
        self.filename = "button{}.txt".format(index+1)
        self.occupied = False

    def clicked(self):
        self.occupied = not self.occupied
        if self.occupied:
            self["bg"] = OCCUPIED
            print("creating file", self.filename)
        else:
            self["bg"] = FREE
            print("deleting file", self.filename)

class Window(tk.Frame):
    def __init__(self, master):
        super (Window, self).__init__(master)
        self.grid()
        self.create_widgets()

    def create_widgets(self):
        for index in range(20):
            button = SeatButton(self, index)
            row, column = divmod(index, 4)
            button.grid(row=row, column=column)

root = tk.Tk()
root.title("Test")
app = Window(root)
root.mainloop()

Too bad that now you've understood what partial() does it's gone...

> Why is it not recommended to to mix the styles if you put the respective
> imports at the
> beginning of the module?

Consistency. Either call the button tk.Button or Button.

_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to