Programmer's Python - Variables, Objects and Attributes
Written by Mike James   
Monday, 02 April 2018
Article Index
Programmer's Python - Variables, Objects and Attributes
Dynamic Attributes

Dynamic Attributes

Once you have a reference to an object you can generally add attributes to it simply by assigning to them.

For example:

MyObject.myNewAttr=2

creates myNewAttr and sets it to the value 2.

In fact, you can create a complete custom object by first creating an object with no attributes and then adding them as required.

For example:

class MyObject:
   pass

MyObject.myAttribute1=0
MyObject.myAttribute2=”test”

and so on. In case you haven’t met it before, pass is the ultimate do nothing instruction in Python. You can use it as placeholder or anywhere an instruction would normally be expected.

Just as it is possible to add attributes you can also remove them using the del command.

For example:

del MyObject.myAttribute2

removes myAttribute2 from MyObject.

If you need to delete an attribute that is determined at run time you can use the delattr function:

delattr(obj,name)

where obj and name are variables.

If you want to know what attributes an object currently has you can use the dir function:

For example:

dir(MyClass)

produces:

['__class__', '__delattr__', '__dict__', '__dir__',
'__doc__','__eq__', '__format__', '__ge__',
'__getattribute__','__gt__', '__hash__',
'__init__', '__init_subclass__','__le__',
'__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__',
'__setattr__','__sizeof__', '__str__',
'__subclasshook__', '__weakref__',
'myAttribute', 'x']

As you can see, a simple object created using the class built-in object has a lot of attributes that you didn’t create. This is because it isn’t a simple custom object in Python; it has a higher purpose which we'll examine in a later chapter.

Nested Objects

Each attribute in an object can reference another object and any attributes in it can reference other objects. That is, nested objects are the norm in Python, although you generally don’t see explicit examples in practice.

For example:

class MyObject1:
    myAttribute1=1
    class MyObject2:
       myAttribute2=2

This looks odd but it works perfectly and makes sense if you think of it as:

MyObject1 = class:
               myAttribute1=1
               MyObject2=Class:
                           myAttribute2=1

This isn’t correct syntax but it makes it look much more like an attribute definition.

Once you have a nested class you have to use a fully qualified name to access the attribute.

For example:

MyObject1.MyObject2.myAttribute2

As this is just a reference you can use a new variable to simplify the name.

For example:

myRef=MyObject1.MyObject2
myRef.myAttribute2

You can always choose to save a reference in a simpler variable to create a shorter name and this is a general principle in Python.

Namespaces and Modules

At this point objects don’t look particularly useful. An object is just a collection of attributes that you can access and attributes are just like variables that you have to access using a qualified name.

This system of qualified names is central to Python and it is part of the object system it implements. When you create an object you also create a namespace. If you know about namespaces then it is worth saying that Python doesn’t quite do it in the same way as other languages. Each object has a Dictionary, i.e. a Python Dictionary data structure, that it uses to store names defined within the object and what they reference.

For example:

class MyObject:
   myAttribute=1

has a Dictionary, which has as an entry myAttribute with the value 1. When you use an instruction like:

MyObject.myAttribute

what happens is that the Dictionary belonging to the object that MyObject references is used to lookup myAttribute. If it finds it, then the value is retrieved and used. Clearly myAttribute defined on the object referenced by MyObject has nothing to do with any other attribute or variable defined in any other object, which is of course the purpose of namespaces.

So it looks as if each object you create makes its own namespace, but notice that because objects don’t have fixed names the prefix can vary.

All variables in Python are part of the namespace, i.e. the Dictionary of the object they are defined in.

What about variables defined at the top level of a program, i.e. not within an object?

The answer to this is that they are within an object – a module object.

A module is a file of code that you can load into the Python system and run. The file has a name that ends in .py and the module has the same name as the file, but without the ,py. The module has a Dictionary and it stores all of the variables defined in the module not within an object, i.e. the global variables.

When you are working within a module the modules’ Dictionary is used by default, but when you load a module into another program you have to use the module’s name as a prefix.

Notice that if there is any executable code, rather than just definitions, then that code is executed as the module is read in.

For example, if you create and save the a file called MyModule.py containing:

class MyObject:
   myAttribute=1
myVariable=2

you can load this module into another module using:

import myModule

This loads the module and its Dictionary. After this you can refer to variables in the module using a qualified name. For example:

print(myModule.myVariable)

If you want to access an attribute on an object you simply use the fully qualified name:

print(myModule.MyObject.myAttribute)

and so on.

Modules behave like objects with attributes consisting of all of the global variable in the module.

Viewed in this way you can see everything really is an object. Even the program that you write and save in a file is a module, which behaves like an object with attributes that are its global variables.

This is also the sense in which there are no global variables, in Python just attributes of modules.

More Modules

The module idea is simple and straightforward, but Python also provides ways for you to modify the way names are made available when you import a module. Notice that none of this gives you anything new, it is just a way of avoiding have to write out fully qualified names.

You can import specific objects within the module and you can change the name of the import by using the as qualifier.

For example:

import myModule.MyObject

imports just the object specified and

import myModule.MyObject as MySecondObj

imports the same object, but changes the variable that references it to MySecondObj.

If you want to get rid of the qualified names you can use from.

For example:

from myModule import MyObject

imports just myModule.MyObject and references it with a variable called MyObject, i.e. no qualified name needed.

You can also change the name of the variable:

from myModule import MyObject as MySecondObj

imports just MyObject and changes the variable to MySecondObj.

Finally, you can use a wildcard character to import everything in a module without changing any variable names:

from myModule import *

This isn’t recommended because of the possibility of name clashes.

Notice that in all cases changing the name of an imported attribute means that the original reference to that attribute isn’t imported.

That is, after:

from myModule import MyObject

you have to refer to MyObject and not myModule.MyObject.

It is also worth noting that a module is only loaded once, no matter how many import statements you use. If you really need to reload a module use the reload function.

There are many variations on importing modules and there is a larger unit called a package which consists of multiple modules. However, the key point is that the idea of the module is part of the everything is an object idea and of the every object has a namespace provided by a Dictionary.

Namespace Access – Advanced Topic

One of the things that is amazing about Python is the way that most of its internal structure is implemented using Python. For example, the namespaces system is implemented using Dictionary objects. What is even more surprising is that the language provides access to most of these features. In particular, you can access the Dictionary object that each object, including a module, has.

Every object has a __dict__ attribute that is its local namespace i.e. it records all of the object's attributes. You can read the namespace and in some cases you can modify it, although it is considered bad practice to do so. In the case of class objects you cannot assign to the __dict__ attribute.

If you try:

print(MyObject.__dict__)

You will see a listing of everything that its Dictionary contains:

{'__module__': '__main__', 'myAttribute': 1,
 '__dict__':
  <attribute '__dict__' of 'MyObject' objects>,
 '__weakref__':
  <attribute '__weakref__' of 'MyObject' objects>,
 '__doc__': None}

Internally an attribute is looked up in the object’s dictionary. That is:

print(MyObject.myAttribute)

is equivalent to:

print(MyObject.__dict__["myAttribute"])

It isn’t often that modifying the Dictionary is useful but it can be useful to check what attributes are defined on an object.

Generally speaking built-in objects don’t allow you to modify their Dictionary it is too dangerous. There are times, however, when being able to change and write new entries in a Dictionary is useful.

Where Next

Perhaps the most important object in all of Python is the function object and yet it is possible to learn to write effective code without ever realizing that it is indeed an object.

Programmer's Python
Everything is an Object
Second Edition

Is now available as a print book: Amazon

pythonObject2e360

Contents

  1. Get Ready For The Python Difference
  2. Variables, Objects and Attributes
  3. The Function Object
  4. Scope, Lifetime and Closure
  5. Advanced Functions
  6. Decorators
  7. Class, Methods and Constructors
      Extract 1: Objects Become Classes ***NEW!
  8. Inside Class
  9. Meeting Metaclasses
  10. Advanced Attributes
  11. Custom Attribute Access
  12. Single Inheritance
  13. Multiple Inheritance
  14. Class and Type
  15. Type Annotation
  16. Operator Overloading
  17. Python In Visual Studio Code

 Extracts from the first edition

Advanced Attributes


raspberry pi books

 

Comments




or email your comment to: comments@i-programmer.info

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

Banner

<ASIN:1435455002>

<ASIN:0672329786>

<ASIN:1590599829>

 



Last Updated ( Wednesday, 27 February 2019 )