3

Set of attributes of an object form a namespace. To access that attribute, you must specify the namespace: obj.attr. Does this mean that attributes of objects are just names defined within a specific namespace (object name)? Or is there a distinction? For instance, references to names in modules are attribute references: in the expression modname.function, modname is a module object and funcname is an attribute of it, (see: 9.2) but when you define a function like the following, there's a clear distinction between the namespace of the function and the attributes of it:

>>> def aFunction():
    x=1
    y=2
    z=3
    #three names have been defined in the local namespace,
    #but aren't considered to be attributes of aFunction from what I understand.

I'm really confused. Can somebody please elaborate on this and explain the difference between an object's namespace and its attributes?

  • 1
    The problem here is your ill-defined notion of "an object's namespace". Functions have an attribute namespace, and each call to a function has a local variable namespace. These are different namespaces, but by thinking in terms of "an object's namespace", you end up mixing up the concepts. There's more than one way a namespace can be conceptually associated with an object. – user2357112 Aug 26 '20 at 10:20

1 Answers1

2

Allow me to quote the documentation:

A namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries, but that’s normally not noticeable in any way (except for performance), and it may change in the future. Examples of namespaces are: the set of built-in names (containing functions such as abs(), and built-in exception names); the global names in a module; and the local names in a function invocation. In a sense the set of attributes of an object also form a namespace. The important thing to know about namespaces is that there is absolutely no relation between names in different namespaces;

So, as @user2357112 supports Monica said in the comments:

There's more than one way a namespace can be conceptually associated with an object.

Kent Johnson also talked about it well:

Another way to think of it is, a namespace is a place where names are looked up. When you use a bare name (not an attribute), it is looked up in the local namespace, then the global namespace, then the built-in namespace. For example:

y = 2  # Defines y in the global (module) namespace

def f():
  x = 1 # Defines x in the local (function) namespace

  # This looks up x, finds it in the local namespace
  # looks up abs, finds it in the built-in namespace
  print abs(x)

  # This looks up y, finds it in the global namespace
  print y

Note that none of the above namespaces have a related __dict__ attribute, the namespace mappings are not stored that way.

Objects also define a sort of namespace, where attributes are defined and looked up. The dict containing the namespace of an object is itself stored as an attribute of the object, called __dict__. So __dict__ is an implementation detail of the way object attributes are stored.

As a beginner, it is important to understand the way bare names are looked up (local, global, built-in namespace) and a bit about the way attributes work. You don't have to be concerned with the implementation details such as __dict__.

You can explore different namespaces using the dir() function, which:

Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object.

def foo(a):
    if a == 3:
        b = 1
    else:
        c = 1
    print("Local function namespace: ", dir())


a = 2
b = 3
foo.custom_attr = "some attr"
foo(a)
foo(b)
print("Global namespace: ", dir())
print("foo object namespace via dir: ", dir(foo))
print("foo object namespace via __dict__: ", foo.__dict__)
print("Built-in namespace: ", dir(__builtins__))

Output:

Local function namespace:  ['a', 'c']
Local function namespace:  ['a', 'b']
Global namespace:  ['__builtins__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b', 'foo']
foo object namespace via dir:  ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'custom_attr']
foo object namespace via __dict__:  {'custom_attr': 'some attr'}
Built-in namespace:  ['ArithmeticError', 'AssertionError', 'AttributeError', [...]
alex_noname
  • 26,459
  • 5
  • 69
  • 86