WEBVTT 1 00:00:01.920 --> 00:00:05.450 so I mentioned at the end of the previous video that there was a useful 2 00:00:05.450 --> 00:00:10.830 application where recursive functions can come in quite handy and that is dealing 3 00:00:10.830 --> 00:00:14.900 with files or specifically getting a directory listing of a computer's file 4 00:00:14.900 --> 00:00:19.650 system now if you think about it modern file systems are recursive in the sense 5 00:00:19.650 --> 00:00:23.500 that a directory can itself contained other directories so once the 6 00:00:23.500 --> 00:00:27.730 functions listed all the objects in in one directory you can call itself again 7 00:00:27.730 --> 00:00:31.760 for all the objects that are themselves directories so you can see that's a 8 00:00:31.760 --> 00:00:38.249 really good use for a recursive function so what we are gonna do is going to use the OS module to get the 9 00:00:38.249 --> 00:00:42.530 directory listing that's also useful for checking if something is a directory so 10 00:00:42.530 --> 00:00:45.549 the function that we gonna write will also have verified that the first directory 11 00:00:45.549 --> 00:00:50.120 passed to it does in fact exist before attempts to do anything else it now before I 12 00:00:50.120 --> 00:00:54.119 go any further theirs another example of recursion and that also 13 00:00:54.119 --> 00:00:59.030 provides an neat way to use a function that's nested within another function if 14 00:00:59.030 --> 00:01:02.889 you really wanted to write a program to visit all subdirectories then the OS 15 00:01:02.889 --> 00:01:07.170 module provides a walk function that will do that for you and in fact I'll 16 00:01:07.170 --> 00:01:12.659 start off with that with the code we are about to write and I just want to bring up the documentation on the screen 17 00:01:12.659 --> 00:01:17.369 because like always its a good habit to get into to check out documentation so 18 00:01:17.369 --> 00:01:24.450 bring it up on the screen paste it in my browser you can see the link there we 19 00:01:24.450 --> 00:01:29.840 go so you can see some pretty useful information about the OS 20 00:01:29.840 --> 00:01:32.840 library that comes as part and parcel of Python 21 00:01:33.600 --> 00:01:41.240 and if we scroll down we should see the os.walk generate the file 22 00:01:41.240 --> 00:01:45.439 names in the directory tree by walking a tree in a top-down or bottom-up so 23 00:01:45.439 --> 00:01:48.399 that's why we are gonna look at so again when in doubt refer to the documentation 24 00:01:48.399 --> 00:01:53.189 its good way of learning more information about any libraries that your 25 00:01:53.189 --> 00:02:02.549 about to use ok so let's go back and I'm gonna create a new module and I'm going to I said module but I'm 26 00:02:02.549 --> 00:02:05.549 gonna create a new Python file I mean so.... 27 00:02:07.650 --> 00:02:16.500 I'm gonna call this one filesanddirectories but it doesn't matter what you call it.....and lets start doing some coding so 28 00:02:16.500 --> 00:02:19.570 so firstly we are gonna import the os because we need to use that library... 29 00:02:22.540 --> 00:02:28.920 we're going to start with the os.walk so..... 30 00:02:28.920 --> 00:02:47.110 .... 31 00:02:52.630 --> 00:02:58.450 ..... 32 00:02:58.450 --> 00:03:04.709 .... 33 00:03:04.709 --> 00:03:17.040 ....so there's our basic applications so the os.walk 34 00:03:17.040 --> 00:03:20.989 function as you can probably gather now returns a list of tuples each tuple 35 00:03:20.989 --> 00:03:25.890 contains a directory name and also 2 lists the first list the name 36 00:03:25.890 --> 00:03:30.060 is directories and you can see that on line 6 because I'm referencing that and 37 00:03:30.060 --> 00:03:33.959 the second one its pretty obvious on line 8 that we're dealing with the list of 38 00:03:33.959 --> 00:03:38.080 files was so there are the 2 list that also included in 39 00:03:38.080 --> 00:03:42.470 the tuple now if you have to work with the file system the os module is worth reading up 40 00:03:42.470 --> 00:03:43.989 on and the 41 00:03:43.989 --> 00:03:47.220 reason is it contains a lot of useful functions including this os.walk one 42 00:03:47.220 --> 00:03:51.910 so to see what walk is actually doing we are going to create our own function 43 00:03:51.910 --> 00:03:55.250 and actually recurse through all subdirectories and print out the contents 44 00:03:55.250 --> 00:03:59.910 but before we do that lets just run it as it is now to see what it actually 45 00:03:59.910 --> 00:04:07.810 does so gonna do that.....and you can see on the right hand side the 46 00:04:07.810 --> 00:04:11.480 output has work so it's obviously defaulted to the current folder and you 47 00:04:11.480 --> 00:04:15.780 can see we got a list of files and theirs actually not really much in the way of 48 00:04:15.780 --> 00:04:18.120 directories their just to confirm that we go back 49 00:04:18.120 --> 00:04:26.560 and have a look in here we click in reveal in finder and go into scope and namespaces and obviously this was the 50 00:04:26.560 --> 00:04:35.669 directory that it was dealing and hasn't really found much hidden files their starting with a dot on a MAC 51 00:04:35.669 --> 00:04:39.479 are hidden which is why we can't see those so let's continue on now 52 00:04:39.479 --> 00:04:44.470 and what we'll do is we'll create a function now and put a bit more 53 00:04:44.470 --> 00:04:48.199 coding into it and will make a look it a bit prettier by indenting the list as 54 00:04:48.199 --> 00:04:51.580 we enter a director etc so lets look at doing that 55 00:04:51.580 --> 00:04:57.380 so gonna come up here and will define a function so... 56 00:04:57.380 --> 00:05:00.380 .... 57 00:05:02.830 --> 00:05:11.510 ..... 58 00:05:12.320 --> 00:05:38.940 .... 59 00:05:38.940 --> 00:05:54.090 .....we are going to write that shortly 60 00:05:54.090 --> 00:05:58.169 so in this particular function we are doing a small amount of initialization the 61 00:05:58.169 --> 00:06:01.620 important bit is obviously making sure that the starting directory that's 62 00:06:01.620 --> 00:06:06.400 passed to this function actually does exist once that's done its gonna call a nested 63 00:06:06.400 --> 00:06:10.690 function that will recursively visit all subdirectories and display its contents 64 00:06:10.690 --> 00:06:15.789 now the thing is the DIR_list function that we are about to 65 00:06:15.789 --> 00:06:20.430 call on line 8 is only actually needed by this function so that's a good 66 00:06:20.430 --> 00:06:25.210 reason for defining it within list directories so basically a function 67 00:06:25.210 --> 00:06:28.120 within a function so here is how we go about doing that 68 00:06:28.120 --> 00:06:33.540 so we actually start in the list _directories function and we type..... 69 00:06:33.540 --> 00:06:46.060 ..... 70 00:06:46.060 --> 00:06:53.040 ...bearing in mind we already validated that the directory 71 00:06:53.040 --> 00:07:00.560 exists and we will by the time we call dir_list and will do a check their so put... 72 00:07:00.560 --> 00:07:04.280 .... 73 00:07:04.280 --> 00:07:17.090 ..... 74 00:07:17.090 --> 00:07:24.220 ....so you can probably gather that one is 75 00:07:24.220 --> 00:07:27.470 doing that's actually putting together the directory and the file and 76 00:07:27.470 --> 00:07:31.039 making a path for it so we are doing a test here then to say whatever that was 77 00:07:31.039 --> 00:07:36.690 actually found is that directory entry because an entry in a particular folder can be 78 00:07:36.690 --> 00:07:41.210 another folder or file so we are doing a check first 79 00:07:41.210 --> 00:07:45.500 to see whether it is a directory I'm using the term folder but obviously directory 80 00:07:45.500 --> 00:07:51.960 and folder are terms interchangeable terms they both mean the same thing so we are 81 00:07:51.960 --> 00:07:56.190 determine that it directory so.... 82 00:07:56.190 --> 00:08:02.360 .... 83 00:08:02.360 --> 00:08:14.289 ...a hint with a tab its going to make things look prettier and be able to indent correctly and 84 00:08:14.289 --> 00:08:20.770 in actual fact the next line......and 85 00:08:20.770 --> 00:08:26.360 we are getting an error their and we'll talk about this shortly so... 86 00:08:26.360 --> 00:08:31.910 so using recursion we are calling back and using the same function again and then we put.... 87 00:08:31.910 --> 00:08:39.180 ..... 88 00:08:39.729 --> 00:08:53.160 .... 89 00:08:53.160 --> 00:08:58.850 ....so that should be our function so basically 90 00:08:58.850 --> 00:09:02.240 each time the inner function in a function rather finds a directory 91 00:09:02.240 --> 00:09:08.290 it increases the tab stopped by 1 and calls itself to visit the new directory now when 92 00:09:08.290 --> 00:09:13.139 it returns it decreases the tab stops so you can see here on line 11 we're at 93 00:09:13.139 --> 00:09:17.209 increases the tab stop it calls the function calls itself again and it 94 00:09:17.209 --> 00:09:23.029 decreases the tab again so it turns out to be much simpler solution than trying to 95 00:09:23.029 --> 00:09:26.690 keep track of which directories which already have been visited and shows 96 00:09:26.690 --> 00:09:31.010 how recursive functions can be very useful when dealing with recursive structures such 97 00:09:31.010 --> 00:09:35.910 as the file system now of course that's all it work of course so it's a good idea 98 00:09:35.910 --> 00:09:40.100 but IntelliJ as you can see on the screen is actually showing errors and obviously 99 00:09:40.100 --> 00:09:42.800 the code isn't going to work at the moment 100 00:09:42.800 --> 00:09:45.959 know if you're familiar with other languages that allowed nested functions 101 00:09:45.959 --> 00:09:49.389 2 such languages are Algol and Pascal 102 00:09:49.389 --> 00:09:54.389 then you maybe a bit confused by the error so it's saying that it can't resolve the 103 00:09:54.389 --> 00:09:58.370 references to tap stop but tab stop is clearly defined in the outer scope as we can see 104 00:09:58.370 --> 00:10:03.079 on line 18 and in fact it looks very similar to the situation we had 105 00:10:03.079 --> 00:10:07.269 with local variables shadowing those with the same name in the outer scope 106 00:10:07.269 --> 00:10:11.699 and that's why IntelliJ was careful to refer them as variables in 107 00:10:11.699 --> 00:10:16.019 the outer scope rather than the global variables so this is the same situation 108 00:10:16.019 --> 00:10:22.889 but the outer scope here is the function list_directories of course that 109 00:10:22.889 --> 00:10:33.980 is defined on line 3 just need to make another line their to get rid of that error and the other thing we are gonna do down here now is 110 00:10:33.980 --> 00:10:40.350 to delete this code we don't need that anymore and we are going to be calling this when we figure 111 00:10:40.350 --> 00:10:43.449 out what's going on here with list_directories with the current folder 112 00:10:46.160 --> 00:10:53.680 so basically the errors that has coming up is unresolved reference tab_stop as you can 113 00:10:53.680 --> 00:11:00.899 see their and that's what's actually causing the problem now if we define a tab_stop on line 114 00:11:00.899 --> 00:11:07.350 within on line within the actual function the inner function we can see what 115 00:11:07.350 --> 00:11:14.389 happens so lets try doing that so....when we do that we 116 00:11:14.389 --> 00:11:20.980 get the error that we've seen before shadows name tab_stop from out of scope and the 117 00:11:20.980 --> 00:11:26.250 reason for that is now we've done that Python's created a local variable called tab_stop 118 00:11:26.250 --> 00:11:30.810 just like it did when we tried to assign it to a global variable in 119 00:11:30.810 --> 00:11:34.199 the blackjack program and as a result its warning us that it's shadowing the 120 00:11:34.199 --> 00:11:39.040 variable in the outer scope which of course is the variable on line 20 which is in the 121 00:11:39.040 --> 00:11:43.850 list_directors function so at this point you might be wondering well maybe 122 00:11:43.850 --> 00:11:49.240 I need to use a global declaration on line 7 to fix this lets try doing that 123 00:11:49.240 --> 00:11:57.649 ....and you notice we got a different error here and will get rid of the equal 0... 124 00:12:01.790 --> 00:12:07.660 and if we try and run this now we actually get an error 125 00:12:07.660 --> 00:12:11.290 you can see the named error is named tab_stop is not defined 126 00:12:11.290 --> 00:12:17.949 so clearly there's still something going on here and the warning here is 127 00:12:17.949 --> 00:12:24.180 that remove redundant parenthesis and so I'll just fix that up and that shouldn't 128 00:12:24.180 --> 00:12:29.699 have an extra bracket their so I am to use to programming on other languages so lets fix that up 129 00:12:29.699 --> 00:12:33.490 at this point even though we know its crash because I have shown you that if we 130 00:12:33.490 --> 00:12:38.709 run this again just to confirm its still crashing we are getting this variable error tab_stop is not 131 00:12:38.709 --> 00:12:42.470 defined and obviously there's now no errors in the program but clearly theirs something 132 00:12:42.470 --> 00:12:47.829 still going on that is causing this error so with Python 2 we would have been 133 00:12:47.829 --> 00:12:51.579 pretty much stuck here now their are ways to get around this and of course we could 134 00:12:51.579 --> 00:12:55.069 just create a global variable but Python 3 introduces another way to 135 00:12:55.069 --> 00:12:58.380 specify the scope of a variable in situations like this 136 00:12:58.899 --> 00:13:03.199 and what we need to do is change the global reference on line 7 to non-local 137 00:13:03.869 --> 00:13:10.559 if we do that we should find it works we type....and now if we run it 138 00:13:10.559 --> 00:13:15.679 you will find its now working correctly you can see the directory listings working we are getting 139 00:13:15.679 --> 00:13:20.050 embedded file names and everything seems to be working better than it did before 140 00:13:20.050 --> 00:13:24.100 so lets end the video here in the next video we're going to continue on we're 141 00:13:24.100 --> 00:13:28.410 going to just sort of talked about why this is working and understanding the scope and 142 00:13:28.410 --> 00:13:32.309 how this non local keyword is helping this to work so see you in the next 143 00:13:32.309 --> 00:13:32.519 video