Python namespaces

Introduction

Python (at least IMO) is a very nice programming language, based on really powerful fundamentals. In this post, I don’t want to compare Python to other programming languages or value it. However, when it comes to the fundamentals of a programming language, Python has some interesting constructs which can differ from other languages. Namespaces are one of those constructs, which can be somewhat difficult to understand if you’re new to Python or when you’re coming from another programming language (e.g. C or Java).

Before we’re digging into Python namespaces, I want to clarify that I’m not that hardcore developer. This is just my attempt to explain Python namespaces to someone who recently started developing Python or is switching from another programming language.

Someone recently asked me:

What are Python namespaces and why do I need them?

To explain it in one single sentence and bring it right to the point:

Python uses namespaces to implement scoping.

Now, I’m aware that sounds somewhat fuzzy, so I try to explain that step by step. To learn more about namespaces, you need to know about encapsulation, scoping and names itself. So, let’s go!

What is a name?

If you start developing Python, you immediately come in contact with its dynamic nature. Because of this awesome feature, you can basically name everything in Python. For example and to keep it simple, you can name a string, number, boolean or list:

my_string  = 'spam and eggs'
my_number  = 42
my_boolean = True
my_list    = ['spam', 'eggs']

Technically these are all objects, but that’s not important right now. Though, because of these fundamentals, you cannot only name simple data types, but you can also name functions:

def spam():
    return 'SPAM SPAM SPAM'

eggs = spam

print(spam())  # SPAM SPAM SPAM
print(eggs())  # SPAM SPAM SPAM

Please note that we didn’t use parenthesis when we were assigning the function spam to the eggs variable. This is really important, as the spam() function is not called at the time of the variable assignment. The following example shows the difference:

def spam():
    return 'SPAM SPAM SPAM'

print(spam)    # <function spam at 0x123456789>
print(spam())  # SPAM SPAM SPAM

As I mentioned before, everything in Python is an object. So, to keep it (really) simple, a variable in Python is just a name or a label which points to an object. But don’t mess up that Python name pointer thingy with memory pointers like you’ll find in C.

What is a namespace?

Obviously, a namespace is a space of names. If you’ve red the official Python tutorial, you’ll find the following definition:

namespace is a mapping from names to objects.

Well, that’s true and this is exactly what a namespace is. It holds names (aka variables) which map to an object. Of course you can also have multiple names per object:

Here’s an example to show that both names point to the same object (in this case a str object):

spam = 'spam and eggs'
eggs = spam

print(spam)  # spam and eggs
print(eggs)  # spam and eggs

print(id(spam))  # 4476916512
print(id(eggs))  # 4476916512

As you can see, namespaces are created automatically by Python. Names can explicitly be defined or they can be imported from other Python modules. I’ll explain that below.

Encapsulation and scoping

In object oriented programming, there’s something called encapsulation, which includes the construct whereas data is bundled with the classes, objects, methods and functions operating on that data. If you read about encapsulation in Python, you’ll often read about namespaces, scopes and finally Python modules.

Now, keep it simple and let’s say a Python module is simply a file containing some Python code. Each Python module has its own global and isolated namespace. Of course you can’t have two identically named functions in one single namespace (Python module), as you’ll have a name clash. However, you can have the same function name defined in two different Python modules, as each module will have it’s own isolated namespace.

This whole “magic” is called scoping, and it’s implemented on several levels. You’ll always have your global module namespace, because of that you can do things like:

spam = 'spam and eggs'
print(spam)

Functions have a separate namespace:

def spam():
    eggs = 'spam and eggs'
    print(eggs)

spam()       # spam and eggs
print(eggs)  # raises a NameError exception

As you can see, you can access the eggs variable within the spam() function, but not outside of it. This is, because eggs was defined in the function’s namespace and is only available in there.

Said that, it’s important to know that namespaces are searched from inside out. This means functions can access the global namespace, but not vice-versa. Thus, if a function can’t find the name in its local namespace, it will try lookup the name in the global namespace:

def spam():
    print(eggs)

eggs = 'spam and eggs'
spam()  # spam and eggs

The spam() function is now accessing the eggs variable from the global namespace, because there’s no eggs variable in its local namespace.

With classes and objects it gets a bit more complicated. However, here’s a (really) simple example:

class Meal:
    def __init__(self):
        self.eggs = 2


my_meal = Meal()
print(my_meal.eggs)    # 2
print(eggs)            # raises a NameError exception

As you can see in the first print line, you can only access the object’s namespace by using the object’s name my_meal.
However, you can’t access the eggs property directly, as it’s only available in the object’s namespace and not in the global namespace.

LEGB

When you read about names, namespaces or scoping in Python, you might see the term LEGB. As you can see, the term is built from 4 different letters, which simply stand for the 4 different Python scopes:

  • Local – Names which are assigned within a function
  • Enclosing – Names which are assigned in a closure (function in a function)
  • Global – Names which are assigned at the top-level of a module, for example on the top-level of your Python file
  • Built-in – Names which are standard Python built-ins, such as open, import, print, returnException

Now as we know the different scopes, we need some rules:

  • The lowest of the scopes is local, therefore the highest is the built-in
  • Lower scopes can always access names in higher scopes
  • Higher scopes can never (directly) access names in lower scopes

This gives us the following graph:

As we now know the scopes and the rules applying for these scopes, we can have a look at some sample code:

Please note, I won’t cover the enclosed scope here, as I’ll introduce you to enclosures in another blog post.

Imports

I’ve already described Python modules (really poorly) before. Now, I’ve told you that each Python module has its own global namespace. But a Python module is pretty useles if you don’t import it, thus we need to have a look at imports. There are several ways to import a Python module and each way will have a different effect.

For the following example, let’s say we’ve a simple Python module called spam.py with the following content:

my_string  = 'spam and eggs'
my_number  = 42

Import spam

Here’s the recommended way to import your whole module into the own global namespace:

import spam

print(spam.my_string)  # spam with eggs
print(spam.my_number)  # 42

As you can see, you can access the module’s namespace by using the module’s name as prefix. This means, the names of the imported Python module are not in our global namespace. Only the imported Python module itself is in our global namespace.

From spam import my_string

You can also import specific names from the Python module into the own global namespace:

from spam import my_string

print(my_string)  # spam with eggs
print(my_number)  # raises a NameError

As you can see, the my_string name was imported while my_number is not available in the own global namespace.

From spam import *

Here’s a way to import all names of your module directly into the own global namespace:

from spam import *

print(my_string)  # spam with eggs
print(my_number)  # 42

As you can see, all names of the spam module are available in the own global namespace, thus no prefix is required.

Please note, that by default all names from a module will be imported when using the  from module import *  syntax. However, you can control which names should be imported via the __all__ list.

So, let’s modify the spam module a bit and add the __all__ list:

__all__ = (
  'my_string',
)

my_string  = 'spam and eggs'
my_number  = 42

Now, if you do the same import as above, you’ll see the full effect of the changes above:

from spam import *

print(my_string)  # spam with eggs
print(my_number)  # raises a NameError

As you can see, the asterisk * now only includes the my_string name, because my_number isn’t included in the __all__ list.

25 Comments

  • bowmasters game

    Thanks for elaborating on these python namespaces. I will get into these.

  • Speedypaper

    Don’t know what is speedypaper? Go to this platform and know what kind of services you can get from this company and if it is really helpful.

  • run 3

    There are two ways to change your life: Start positive actions and stop negative actions.

  • scribble io

    I want to study but without formal study it is difficult

  • cherry u

    It’s really hard for me to comprehend this

  • https://dumpsterrentalcga.com

    Usually I do not read article on blogs, but I wish to say that this write-up very pressured me to take a look at and do so! Your writing taste has been surprised me. Thank you, quite great post.

  • Visit us

    Namespace are easy to understand in Python, this guide is useful as well!

  • Landscaping company

    Your new valuable key points imply much a person like me and extremely more to my office workers. With thanks; from everyone of us.

  • https://thedentaz.com

    Loving the information on this site, you have done great job on the blog posts.

  • Contractor

    Not quite familiar with python namespace, but what I know is that this is a good programming language.

  • bandarqq

    Definitely feel whatever you stated. Your chosen justification appeared to be around the web the particular simplest factor to be familiar with. My partner and i say to an individual, My partner and I definitely acquire irked although folks consider problems which they plainly do not find out about. An individual was able to strike the particular toenail after the most notable and identified out there the whole lot with no side effect, folks can require a signature. Can likely become again to obtain additional. Thank you.

  • émondage

    Good to know that the previous bug has been fixed now and it’s working great on my droid, too! Thanks for this useful entry!

  • Thank you so much for sharing this great blog. Very inspiring and helpful too. Hope you continue to share more of your ideas. I will definitely love to read…