1

I am learning Python. I have come to the point were my functions, that have loops can't call other functions from within the loop because otherwise I get duplicate results, so I want to create a function that calls each function, gets the data out of them and assigns them to functions that execute after and need that data to work, avoiding looping.

So let's say I have this function :

def get_sound():
    for dirpath, directories, files in os.walk(XPATH):
        for sound_file in files:
            date = artist = album = title = ""
            if sound_file.endswith('.flac'):
                print('Flac file found, getting metadata and renaming...')
                flac_file = os.path.join(dirpath, sound_file)
                from mutagen.flac import FLAC
                metadata = mutagen.flac.Open(flac_file)
                for (key, value) in metadata.items():
                    if key.startswith("date"):
                        date = value[0]
                    if key.startswith("artist"):
                        artist = value[0]
                    if key.startswith("album"):
                        album = value[0]
                    if key.startswith("title"):
                        title = value[0]
                final_name = (date + " - " + artist +
                              " - " + album + " - " + title)
                dest_file = os.path.join(dirpath, final_name)
                os.renames(flac_file, dest_file)
                return (dest_file, final_name, artist, album, title)

From that function, I got a tuple of data. Now, what I want to do is to create a function :

def main():
    get_sound()
    find_key()
    make_video()

get_sound() will return data, find_key() will also return data, and make_video() will use both data to fill certain variables and execute a command with them. As the data returned has no identifier, how do I pass get_sound() and find_key() returned data to make_video ?

xavier
  • 746
  • 2
  • 12
  • 22
  • I'm not sure if I understand your question. Just assign it to a variable...? `sound = get_sound()`? – x squared Feb 06 '16 at 09:54
  • I am returning variables, what I want to do is to pass those variables to make_video() because it will use them ... – xavier Feb 06 '16 at 09:57

2 Answers2

3

A function call (e.g. get_sound()) represents the value that the function returns. You can assign that value to a variable and use that value in subsequent operations and function calls:

def main():
    sound = get_sound()
    key = find_key()
    make_video(sound, key)

Or you can use the functions in place of their return values within operations and function calls:

def main():
    make_video(get_sound(), find_key())

This assumes that make_video takes two positional arguments, where the first can be a tuple as returned by get_sound. So make_video might look somewhat like this:

def make_video(audio, key):
    audio_destination_file, audio_name, audio_artist, audio_album, audio_title = audio
    # Do something with audio_destination_file, audio_name, audio_artist,
    # audio_album, audio_title and key ...

If instead your make_video function expects the components of the get_sound return value as separate arguments, like so:

def make_video(audio_destination_file, audio_name,
               audio_artist, audio_album, audio_title, key):
    # Do something

... then either explicitly unpack them before the call like x squared suggests or use the splat operator for unpacking when calling:

def main():
    sound = get_sound()
    key = find_key()
    make_video(*sound, key)

or

def main():
    make_video(*get_sound(), find_key())
Community
  • 1
  • 1
das-g
  • 9,718
  • 4
  • 38
  • 80
  • Ok, got that. The problem is that get_sound() returns data that will be used also on other functions, meaning that not all that data will used by make_video(). Is this bad design ? For example, ```make_video()``` will use only ```dest_file``` and ```final_name```. ```artist, album, title``` were meant to be used by another function. Do I have to rewrite the code so each function returns only one variable ? – xavier Feb 06 '16 at 10:11
  • You don't _have_ to rewrite your code so each function returns only one variable. Just use unpacking (`dest_file, final_name, artist, album, title = get_sound()`), then use the resulting variables as arguments for those other functions. But splitting the function up into smaller, independent parts might indeed be better design. – das-g Feb 06 '16 at 10:21
  • 1
    That being said, don't worry about design too much while you're still learning the basics. While it's never too early to start thinking about good and bad design, try to do one thing at a time: First, get a small part of code to _work_ (and by that, I mean to work _correctly_), and _only then_ try to get it _right_ (from a design/style perspective), keeping it working correctly. Then proceed to write the next small part of code the same way (make it work, then make it right). – das-g Feb 06 '16 at 10:29
  • Ok, I understand it now. Thank you so much for your extended answer and the time invested ! – xavier Feb 06 '16 at 10:51
  • Is the splat operator a wildcard that gets all the returned variables, or just the data inside those variables ? It looks like grouping all the returning variables in to a new variable. – xavier Feb 06 '16 at 13:39
  • 1
    When used in a function call (like you would here), the `*`-operator performs [positional argument unpacking](https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument-lists), [a.k.a.](http://stackoverflow.com/a/2323312/674064) positional expansion. When used in a function definition's signature, it does the reverse: It allows the function to accept an arbitrary number of positional arguments and [packs them all](https://docs.python.org/2/tutorial/controlflow.html#arbitrary-argument-lists) into the argument variable it is applied to (usually called `args` by convention.) – das-g Feb 06 '16 at 17:43
  • Amazing. I will read that in depth. Thank you for your efforts das-g. – xavier Feb 07 '16 at 02:42
2

Depends on how make_video()s parameters look like. If it takes a tuple as argument its:

make_video(get_sound(), find_key())

Or if it takes single arguments you can assign multiple variables with the return value, e.g:

(dest_file, final_name, artist, album, title) = get_sound()
make_video(dest_file, final_name, artist, album, title, find_key())
x squared
  • 3,173
  • 1
  • 26
  • 41
  • ```make_video``` is an ffmpeg subprocess command and it needs only two of the returned variables. The other variables returned were meant to be used by yet another function. Should I make each function return only the variables that will be used by another function then ? – xavier Feb 06 '16 at 10:17
  • 1
    Ah, I thought `make_video()` is a function by you. But yeah, it depends on your program which return values make sense. For example you can return everything now and use the last two return values later. Or you split `get_sound()` into two functions. Both is possible. Although the name of `get_sound()` is a little misleading, when it also returns the artist and album title. – x squared Feb 06 '16 at 10:23
  • Thank you for helping x squared ! – xavier Feb 06 '16 at 10:51