0

I have a program that downloads video files Here it is in full, don't worry its a short program.

import pafy

def download():
    url = raw_input('Please enter the path to the video\n')
    video = pafy.new(url)
    vid_title = video.title
    best = video.getbest()
    streams = video.streams
    print(vid_title)
    for stream in streams:
        print(stream)
    print'Resolution: ',best.resolution,'\nExtension : ', best.extension
    user_choice = raw_input("Do you want to download this video\ny or n\n")
    if user_choice == 'y':
        print'Your video will downloaded soon'
        filename = best.download(filepath = '/home/mark/new_projects')
        another_download()
    elif user_choice =='n':
        print'You have chosen not to download a video'
        another_download()


def another_download():
    another_choice = raw_input('Would you like to download another video\ny or n\n')
    if another_choice == 'y':
        download()
    else:
        print'Thank for using my program'

download()

I would like to break it down into smaller functions. I have tried to do this:

def url():
    url = raw_input('Please enter the path to the video\n')
    video = pafy.new(url)
    vid_title = video.title
    best = video.getbest()
    streams = video.streams
    print(vid_title)
    for stream in streams:
        print(stream)
    print'Resolution: ',best.resolution,'\nExtension : ', best.extension

def download():
    user_choice = raw_input("Do you want to download this video\ny or n\n")
    if user_choice == 'y':
        print'Your video will downloaded soon'
        filename = best.download(filepath = '/home/mark/new_projects')
        another_download()
    elif user_choice =='n':
        print'You have chosen not to download a video'
        another_download()

But when I try this I get an error telling me that best has not been declared. I don't want to declare best as a global variable. Is there a way of using a variable from one function inside another function?

Anil_M
  • 10,893
  • 6
  • 47
  • 74
Mark Kelly
  • 27
  • 1
  • 9
  • Can you show your method resolution order? I mean, from where `download()` is called and when, same about `url()`. Just provide a full program in the second example, too. –  Aug 18 '16 at 15:40
  • 1
    And yes, there is a way to use one variable from one function inside another function. Use a *parameter*. –  Aug 18 '16 at 15:42
  • @light2yellow Thanks, I did try to use a parameter, but I was not doing it correctly that's why I came here. I called both url() and download at they end of the file – Mark Kelly Aug 18 '16 at 15:58
  • you should design your program to work in a bit more strict manner - call either download or url, whatever you decide to be your main function. And inside that main function make a call to another function, passing it an argument, which has been prepared by the main function already. Doing this way will make it possible to share data between multiple functions. So, just plan ahead, what function will be the main one and call the second one from inside it. Call the main function at the end of the file. –  Aug 18 '16 at 16:25
  • @light2yellow Thank you very much. That was very helpful – Mark Kelly Aug 18 '16 at 16:33
  • you're welcome! Next time you'll write some piece of code - think first about a hierarchy of the calls. This is one of the most essential things, because it allows you to keep all the data in one scope and then call smaller functions to bustle a bit with the data. –  Aug 18 '16 at 16:38

2 Answers2

0

Split a big function into smaller ones is a good habit but a more urgent problem is that you should use a main loop and make your functions return instead of chaining them like that.

Right now download() -> another_download() -> download() -> another_download() -> download() -> ..., so if the user wants to download n vids you'll have n * 2 - 1 functions hanging around until the last one finish.

Incidentally return solves your problem :

def url():
    ...
    return best 

def download():
    best = url()
    ...
polku
  • 1,575
  • 2
  • 14
  • 11
0

There are a couple options for you here. I will try and lay them out best I can.

Option 1: Assuming you are calling download() first, you can have url() return what you need and store that in a variable in the download() method:

def url():
    url = raw_input('Please enter the path to the video\n')
    video = pafy.new(url)
    vid_title = video.title
    best = video.getbest()
    streams = video.streams
    print(vid_title)
    for stream in streams:
        print(stream)
    print'Resolution: ',best.resolution,'\nExtension : ', best.extension
    return best

def download():
    user_choice = raw_input("Do you want to download this video\ny or n\n")
    if user_choice == 'y':
        best = url()
        print'Your video will downloaded soon'
        filename = best.download(filepath = '/home/mark/new_projects')
        another_download()
    elif user_choice =='n':
        print'You have chosen not to download a video'
        another_download()

Option 2: You could use global variables, though I don't know the ramifications of using them in this case:

best = None
def url():
    global best
    url = raw_input('Please enter the path to the video\n')
    video = pafy.new(url)
    vid_title = video.title
    best = video.getbest()
    streams = video.streams
    print(vid_title)
    for stream in streams:
        print(stream)
    print'Resolution: ',best.resolution,'\nExtension : ', best.extension

def download():
    global best
    user_choice = raw_input("Do you want to download this video\ny or n\n")
    if user_choice == 'y':
        print'Your video will downloaded soon'
        filename = best.download(filepath = '/home/mark/new_projects')
        another_download()
    elif user_choice =='n':
        print'You have chosen not to download a video'
        another_download()

I think either of these solutions will give you what you want, but I would recommend the first in this specific case as it doesn't seem like a complex program.

Michael Platt
  • 1,297
  • 12
  • 25