This is some code I wrote for a music program... Any way on making it neater/more pythonic?

from Tkinter import *
import pygame
playlist=[]
pygame.init()
pygame.mixer.init()
camera=pygame.mixer.Sound("E:\\Peter\\Python_stuff\\data\\Music\\camera1.wav")
one=pygame.mixer.Sound("E:\\Peter\\Python_stuff\\data\\Music\\one.wav")
wrong=pygame.mixer.Sound("E:\\Peter\\Python_stuff\\data\\Music\\wrong.wav")
root=Tk()
root.title("DJ Pro")
def sound_play(event=None):
    playlist.append(wrong)
    wrong.play()
def sound_play1(event=None):
    playlist.append(one)
    one.play()
def sound_play2(event=None):
    playlist.append(camera)
    camera.play()
def play_all(event=None):
    for ii in playlist:
        ii.play()
        while True:
            if not pygame.mixer.get_busy():
                break
def reset(event=None):
    global playlist
    playlist=[]
sound1=Button(master=root, text="wrong", command=sound_play)
sound1.pack()
sound2=Button(master=root, text="one", command=sound_play1)
sound2.pack()
sound3=Button(master=root, text="camera", command=sound_play2)
sound3.pack()
sound4=Button(master=root, text="play", command=play_all)
sound4.pack()
sound5=Button(master=root, text="restart", command=reset)
sound5.pack()
root.mainloop()

thanks!
edit: Also, is there an audio package for combining music files? It is possible to do it by removing meta-data then combining them but I'd rather not...

Whitespace is recommended to make Python code clearer. Traditionally there is no space between related lines of code. A single line is recommended between different code sections and function definitions. Two lines are recommended between class definitions and I use two lines in method declarations if the methods are different enough to be logically separated. (For instance, I'll write my methods for accessing one property, and then I'll enter two blank lines and type more methods for accessing another property.)

I might have considered importing just the specific function I needed from pygame.mixer, or importing all functions and attributes.

I don't think you've been introduced to Python's object oriented features yet, but I probably would have used a few classes too to simplify some things.

Also, "if __name__ == '__main__'" is understood to be a standard Python idiom that you should research.

There are a few questions I have.

When you add a sound to the playlist, you automatically play it. Is that the functionality you desire?

When you add a sound to the playlist, you automatically play it. Is that the functionality you desire?

Yes, as sound.play() is not necessary for adding to the playlist.

Also, "if __name__ == '__main__'" is understood to be a standard Python idiom that you should research.

I have heard of this and understand this. Although I doubt I'll be importing my module...

I have heard of this and understand this. Although I doubt I'll be importing my module...

Understandable, but something I do is keep a basic python file that I can copy and edit on the fly.

#!/usr/bin/env python

def main():
    pass

if __name__ == "__main__":
    main()

The line at the beginning is a comment for the courtesy of Linux users. It is called a shebang, and it lets the Linux OS know where the Python interpreter is so that when a Linux user executes the file it is automatically opened with the interpreter. It does not affect people who use other operating systems.

You don't have to remove the pass statement in main() to add code. Simply write after it. I include the pass statement to prevent an exception if the script is executed as a program, even if there is no main() code.

I don't think the main() function is exactly Pythonic, but I use it so that I don't pollute the global namespace.

To each their own I guess.

Here's how I would've written it using functional programming.

It's not necessarily the best way to do it, it's just the way I would have done it. I've included some commentary in the program comments that you should read over.

If I find the time I would like to show you the same program written using object oriented code, but object oriented code requires more thought up front than functional code. The rewards are worth it though and can speed up development later in the software cycle.

Some people might disagree with my style, and they have the right to their opinions, but if you want to learn about style from people that are true leaders in the Python community - someone in the know - then refer to PEP 8.

http://www.python.org/dev/peps/pep-0008/

#!/usr/bin/env python

from Tkinter import *
import pygame.mixer
from pygame.mixer import Sound

pygame.mixer.init()

"""According to pygame documentation, initiating pygame is unnecessary
if you are only using a module within the package. In that case only initiating
the module you are using is necessary. It can sometimes be faster."""

playlist = []

CAMERA_SOUND = Sound(r'e:\Peter\Python_stuff\data\Music\camera1.wav')
ONE_SOUND = Sound(r'e:\Peter\Python_stuff\data\Music\one.wav')
WRONG_SOUND = Sound(r'e:\Peter\Python_stuff\data\Music\wrong.wav')

"""Raw strings allow you to type special characters without escaping them.
To create a raw string, simply prepend the r character before the string,
or wrap the string in triple quotes.
Python variable names are generally nouns describing the object.
Descriptive names are longer but more informative.
The general naming convention for variables is lowercase words separated by single underscores.
Variables intended to be constant are words in all caps separated by single underscores."""


def main():
    pass


    def add_camera_sound(event = None):
        global playlist
        global CAMERA_SOUND
        playlist.append(CAMERA_SOUND)
        CAMERA_SOUND.play()

    """Use the global statement to be able to access global variables within a
    function.
    Functions generally are a verb and a predicate describing what the function does.
    Function names generally are lowercase words separated by single underscores."""

    def add_one_sound(event = None):
        global playlist
        global ONE_SOUND
        playlist.append(ONE_SOUND)
        ONE_SOUND.play()

    def add_wrong_sound(event = None):
        global playlist
        global WRONG_SOUND
        playlist.append(WRONG_SOUND)
        WRONG_SOUND.play()

    def play_all(event = None):
        global playlist
        for sound in playlist:
            sound.play()
            while True:
                if not pygame.mixer.get_busy():
                    break

    def empty_playlist(event = None):
        global playlist
        playlist = []

    root = Tk()
    root.title('DJ Pro')

    camera_sound_btn = Button(master = root, text = 'camera', command = add_camera_sound)
    camera_sound_btn.pack()

    one_sound_btn = Button(master = root, text = 'one', command = add_one_sound)
    one_sound_btn.pack()

    wrong_sound_btn = Button(master = root, text = 'wrong', command = add_wrong_sound)
    wrong_sound_btn.pack()
    
    play_all_btn = Button(master = root, text = 'play', command = play_all)
    play_all_btn.pack()

    empty_playlist_btn = Button(master = root, text = 'empty', command = empty_playlist)
    empty_playlist_btn.pack()

    root.mainloop()


if __name__ == "__main__":
    main()

That helped me very much :)... Now all I need is a way to only write one function (if I support lots of sounds and user-sound-uploading)!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.