So, we're importing the turtle module in order to use it in our code.
So I want to spend a few minutes just quickly talking about all the ways that we can import
modules.
So we've already seen the Basic Import and it's very simple,
we have the keyword import and then we have the Module name that we want to import.
So if we had just imported our turtle module with the simple import, then in order to create
a new turtle, we would have to say the module name and then the name of the class,
and we would create a new turtle like this.
Now this is perfectly fine, but it would make it so much more convenient if we were using
that Turtle class a lot to write our code like this.
This way, we don't have to keep writing turtle.Turtle() or turtle.Whatever else it is that we want
to import.
And this code is again pretty simple,
we have the keyword "from", we have the keyword "import", we have the Module name, and also the
Thing in the module that we want to import.
As you've seen, with this kind of syntax, we can simply write...
And this means that if we were creating a lot of turtles, let's say, instead of just
creating tim, we also created tom and terry, then we don't have to keep writing turtle.Turtle(),
turtle.Turtle() every single time.
So this from import is really helpful if you're going to use this thing that you're importing
a lot and you don't want to keep writing the name of the module in front of it.
Now you can actually go one step further,
instead of saying just from turtle import whatever it is you want, you can actually
import everything by using the asterisk.
Now you can use everything that's in that module as if it were in the current file.
And this has advantages as well as disadvantages, because it can make it really hard to see
where each of these classes or methods come from.
So for example, if I just wrote forward(), you can see I can, I can do this,
but it's really confusing to just see this method somewhere in isolation, because it's
like, "Well, what is moving forward?
What's actually happening?
Where does this come from?"
And it's more obvious when you import a module like random.
So from random import everything.
And then somewhere else in our code, we might just write something like, choice(),
and this is a method from random, where we can pick a random item from a sequence like
a list.
Now this code works, but it's really confusing.
Like, "How is this choice() working?
Where does it come from?
Which module enables this capability?"
Instead we just have the method whack right in our code,
and it's very confusing as to its origins.
So amongst the Python community, it's very unusual that you'll see good code written
like this.
I want you to know what it does, because you might come across it in the wild, just so
you understand what it's actually doing,
but I want you to try and avoid writing code like this.
Instead, if you're using something from a module many times, so more than three times,
then you can think about using this "from import",
but if you're only using it once or twice, then just import the whole module and write
out this turtle.Turtle().
So you can see that this module is the one that contains this class and that is imported
and we're using it to create this object.
It's just a lot more expressive in terms of the code.
Now the final thing I want to show you, which is quite a useful thing, is how to Alias Modules.
So for example, we can import our turtle as "t".
So what this does is we import from the turtle module and we give that module an alias name,
so a name that we define.
And what this means is that if you were to create your new object from the module turtle,
instead of writing out turtle every single time, you can just write "t", and it will represent
the entire module.
So sometimes you'll have modules which are really, really long.
So it could have a really long name and you don't want to type it out every single time.
So you give it an alias name and it will be exactly the same as referring to the entire
name of the module.
And you can create a turtle like this.
Now, even though we've been writing import, there are some modules that you can't just import, right?
So for example, if I wanted to import the heroes module, which is something that I can
use to generate hero names like Decepticon or Leopardon or Askew-Tronics, then I can use
one of the functions that's in that module, heroes, called generate.
But if I just go into my code and I straight up try to import this module, which is called
heroes, then you can see I get an error and the error says, there's "No module named heroes."
Why is it that I can't do this, but I can import turtle?
Well, the reason is because turtle is a module that's packaged with the Python standard library,
and this is a small library of code which contains just the basics to get you started.
Like a core set when you buy a board game or like the basic track pieces when you buy
a set of Hot Wheels.
So you can imagine this library of code as like a family library, easily accessible,
but very small.
Now, if we wanted to access the whole world of Python modules and packages, then we need
to go to a much bigger library.
And that is, of course, the Python packages, which are hosted on the internet and we can
install into our project as and when we need them.
So this way, our final project doesn't become gigantic because we've got all of the modules
loaded into it from the internet,
instead, we only plug and play whatever it is we need.
So PyCharm is actually already smart enough to know that I probably want a module that
I haven't installed.
And you can see that as soon as I click on this error with the red underline, I get a
red light bulb over here.
And if I click on it, it gives me the prompt to install this package called heroes.
And once it's done, then we can actually tap into this module and we can say heroes.gen(),
and this is going to generate us a new hero name.
So let's go ahead and run our code.
And you can see we've got a name called Galvatron, which is not bad, actually.
So it's important to remember that when you try to import something that hasn't been installed,
like this villains package, then when you try to run the code, you'll get an error that
says, "No module named villains".
And this should prompt you to think, "Uh, maybe that module is not a part of the Python standard
library like turtle, and I actually have to install it."
Just remember that before you can import a module, sometimes if it's not bundled with
the Python standard library, then you might have to install it.
Now what happens when you install a package is it gets installed into the local virtual
environment, which as we said previously, is on a per project basis.
So this is stored in the .venv or virtual environment folder,
and you can see it here, heroes and villains, as well as other modules in Python.
Now, for the most part, you don't need to touch this folder at all,
you can leave it as it is already set up for you.
And when you create new projects in PyCharm, it usually gets created automatically for you.
So this is an important differentiation between modules, like what we import here, and software.
So when you install software, for example, PyCharm, you only need to install it once
and it's available globally across your computer.
Now with a virtual environment, and with these packages, they get installed into the project
that you're building.
So for example, today we're building day-18-start, and these two modules are available
in this project,
but if I was to start a new project,
then you'll see that those packages are not installed by default.
So they're not global.
The reason why we need to work with virtual environments when using Python is actually
a bit of a historical problem.
So previously, there was a version of Python called Python 2,
and then people wanted new features to Python, so they created Python 3.
However, sadly, Python 3 is not what we call backward-compatible with Python 2.
So it means that if you have code that's written in Python 2, and then you try to add Python
3 to that project, it's not going to work.
So you kind of have to make a choice, either Python 2 project, or projects written in Python
3.
Now, we all know that Python 3 is the future,
but that doesn't mean that there isn't a lot of existing projects written in Python 2.
So the transition has been really, really slow,
and virtual environments help us in a way by defining a small sandbox for our project.
So we can decide whether we want to use Python 2 or Python 3 for our project,
and then because we're in a virtual environment, we can install the modules that we need, for
example, the heroes module, which works with Python 3, but not Python 2.
And we know that because we have our virtual environment set up for each and every project,
and it's different for every single project, then when we install each module, we know
that it's compatible,
we know that that particular version works with all of the other packages that we have
installed,
and it's kind of like freezing that project in time, so that you know, once you compile
everything, once your program runs, you can continue running that program as and when
you want, even if things like Python change versions, or your modules change versions.
So that's one of the reasons why we want to use PyCharm to handle and install our modules,
because it means that it works with the rest of our virtual environment.
It ensures that there are no errors that occur when we install it.
And we maintain the version that we use, so that our final project works as expected.
Now some of you might have seen that you can also install these packages using pip.
So you could go into the terminal and write "pip install..." and pick one of these projects.
But as you can imagine, with virtual environments, with the different projects having different
virtual environments, you might install these modules into the wrong location,
and that means your project won't be able to access them outside of the sandbox.
So I recommend following the video and doing what I do in the videos, so that we can all
be on the same page and we can all learn as quickly as possible.