- Function: Something that performs and action when you call it with zero or more `arguments`. A function is stand-alone in a python module, like `print()`
The point is that even if the values of the stats change, the print() statement would not change - it just keeps pretty-printing whatever is given to it.
the `key=value` pairs we add are called _keyword arguments_ for the `format()` method. Each named argument will go to the matching `{key}` in the string. When using keywords, the order we add them doesn't matter. We have no `{dext}` and two `{stren}` in the string, and that works fine.
Using `.format()` is convenient (and there is a [lot more](https://www.w3schools.com/python/ref_string_format.asp) you can do with it). But the _f-string_ can be even more convenient. An
Use the commands `color ansi` or `color xterm` to see which colors are available. Experiment! You can also read a lot more in the [Colors](../../../Concepts/Colors.md) documentation.
The `.py` ending of `test.py` is never included in this "Python-path", but _only_ files with that ending can be imported this way. Where is `mygame` in that Python-path? The answer is that Evennia has already told Python that your `mygame` folder is a good place to look for imports. So we should not include `mygame` in the path - Evennia handles this for us.
You will *not* see any output this or any subsequent times! This is not a bug. Rather it is because of how Python importing works - it stores all imported modules and will avoid importing them more than once. So your `print` will only run the first time, when the module is first imported.
> We'll get back to more advanced ways to import code in [a later lesson](./Beginner-Tutorial-Python-classes-and-objects.md#importing-things) - this is an important topic. But for now, let's press on and resolve this particular problem.
We want to be able to print our hello-world message at any time, not just once after a server
reload. Change your `mygame/world/test.py` file to look like this:
```python
def hello_world():
print("Hello World!")
```
As we are moving to multi-line Python code, there are some important things to remember:
- Capitalization matters in Python. It must be `def` and not `DEF`, `who` is not the same as `Who`.
- Indentation matters in Python. The second line must be indented or it's not valid code. You should
also use a consistent indentation length. We *strongly* recommend that you, for your own sanity's sake,
set up your editor to always indent *4 spaces* (**not** a single tab-character) when you press the TAB key.
So about that function. Line 1:
-`def` is short for "define" and defines a *function* (or a *method*, if sitting on an object).
This is a [reserved Python keyword](https://docs.python.org/2.5/ref/keywords.html); try not to use
these words anywhere else.
- A function name can not have spaces but otherwise we could have called it almost anything. We call
it `hello_world`. Evennia follows [Python's standard naming style](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md#a-quick-list-of-code-style-points)
with lowercase letters and underscores. We recommend you do the same.
- The colon (`:`) at the end of line 1 indicates that the header of the function is complete.
Line 2:
- The indentation marks the beginning of the actual operating code of the function (the function's
*body*). If we wanted more lines to belong to this function those lines would all have to
start at least at this indentation level.
Now let's try this out. First `reload` your game to have it pick up
our updated Python module, then import it.
> reload
> py import world.test
Nothing happened! That is because the function in our module won't do anything just by importing it (this
is what we wanted). It will only act when we *call* it. So we need to first import the module and then access the
function within:
> py import world.test ; world.test.hello_world()
Hello world!
There is our "Hello World"! As mentioned earlier, use use semi-colon to put multiple
Python-statements on one line. Note also the previous warning about mud-clients using the `;` to their
own ends.
So what happened there? First we imported `world.test` as usual. But this time we continued and
accessed the `hello_world` function _inside_ the newly imported module.
By adding `()` to the `hello_world` function we _call_ it, that is we run the body of the function and
print our text. We can now redo this as many times as we want without having to `reload` in between:
> py import world.test ; world.test.hello_world()
Hello world!
> py import world.test ; world.test.hello_world()
Hello world!
## Sending text to others
The `print` command is a standard Python structure. We can use that here in the `py` command since
we can se the output. It's great for debugging and quick testing. But if you need to send a text
to an actual player, `print` won't do, because it doesn't know _who_ to send to. Try this:
> py me.msg("Hello world!")
Hello world!
This looks the same as the `print` result, but we are now actually messaging a specific *object*,
`me`. The `me` is a shortcut to 'us', the one running the `py` command. It is not some special
Python thing, but something Evennia just makes available in the `py` command for convenience
(`self` is an alias).
The `me` is an example of an *Object instance*. Objects are fundamental in Python and Evennia.
The `me` object also contains a lot of useful resources for doing
things with that object. We access those resources with '`.`'.
One such resource is `msg`, which works like `print` except it sends the text to the object it
is attached to. So if we, for example, had an object `you`, doing `you.msg(...)` would send a message
to the object `you`.
For now, `print` and `me.msg` behaves the same, just remember that `print` is mainly used for
debugging and `.msg()` will be more useful for you in the future.
## Parsing Python errors
Let's try this new text-sending in the function we just created. Go back to
your `test.py` file and Replace the function with this instead:
```python
def hello_world():
me.msg("Hello World!")
```
Save your file and `reload` your server to tell Evennia to re-import new code,
then run it like before:
> py import world.test ; world.test.hello_world()
No go - this time you get an error!
```python
File "./world/test.py", line 2, in hello_world
me.msg("Hello World!")
NameError: name 'me' is not defined
```
```{sidebar} Errors in the logs
In regular use, tracebacks will often appear in the log rather than
in the game. Use `evennia --log` to view the log in the terminal. Make
sure to scroll back if you expect an error and don't see it. Use
`Ctrl-C` (or `Cmd-C` on Mac) to exit the log-view.
```
This is called a *traceback*. Python's errors are very friendly and will most of the time tell you
exactly what and where things go wrong. It's important that you learn to parse tracebacks so you
know how to fix your code.
A traceback is to be read from the _bottom up_:
- (line 3) An error of type `NameError` is the problem ...
- (line 3) ... more specifically it is due to the variable `me` not being defined.
- (line 2) This happened on the line `me.msg("Hello world!")` ...
- (line 1) ... which is on line `2` of the file `./world/test.py`.
In our case the traceback is short. There may be many more lines above it, tracking just how
different modules called each other until the program got to the faulty line. That can
sometimes be useful information, but reading from the bottom is always a good start.
The `NameError` we see here is due to a module being its own isolated thing. It knows nothing about
the environment into which it is imported. It knew what `print` is because that is a special
[reserved Python keyword](https://docs.python.org/2.5/ref/keywords.html). But `me` is *not* such a
reserved word (as mentioned, it's just something Evennia came up with for convenience in the `py`
command). As far as the module is concerned `me` is an unfamiliar name, appearing out of nowhere.
Hence the `NameError`.
## Passing arguments to functions
We know that `me` exists at the point when we run the `py` command, because we can do `py me.msg("Hello World!")`
with no problem. So let's _pass_ that me along to the function so it knows what it should be.
Go back to your `test.py` and change it to this:
```python
def hello_world(who):
who.msg("Hello World!")
```
We now added an _argument_ to the function. We could have named it anything. Whatever `who` is,
we will call a method `.msg()` on it.
As usual, `reload` the server to make sure the new code is available.
Note that we didn't need to put `py` in front now. The system will also echo your input (that's the bit after the `>>>`). For brevity in this tutorual we'll turn the echo off. First exit `py` and then start again with the `/noecho` flag.
To that end we also created a first new Python module in the `mygame/` game dir, then imported and used it. Now let's look at the rest of the stuff you've got going on inside that `mygame/` folder ...