3

In Python, I want to have a class attribute, a dictionary, with initialized values. I wrote this code:

class MetaDataElement:
    (MD_INVALID, MD_CATEGORY, MD_TAG) = range(3)
    mapInitiator2Type = {'!':MetaDataElement.MD_CATEGORY, 
                         '#':MetaDataElement.MD_TAG}

But when I try to run this code, I get an error message with "NameError: name 'MetaDataElement' is not defined". Could you help me?

Thanks in advance.

Marcin
  • 48,559
  • 18
  • 128
  • 201
redism
  • 500
  • 7
  • 18

2 Answers2

3

You cannot refer to MetaDataElement while it is being constructed, since it does not yet exist. Thus,

class MetaDataElement:
    (MD_INVALID, MD_CATEGORY, MD_TAG) = range(3)
    mapInitiator2Type = {'!':MetaDataElement.MD_CATEGORY, 
                         '#':MetaDataElement.MD_TAG}

fails because the very construction of mapInitiator2Type requires MetaDataElement to have attributes, which it does not yet have. You can think of your constants MD_INVALID, etc. as variables that are local to the construction of your class. This is why the following works, as icktoofay wrote:

class MetaDataElement:
    (MD_INVALID, MD_CATEGORY, MD_TAG) = range(3)
    mapInitiator2Type = {'!': MD_CATEGORY,  # MD_CATEGORY is like a local variable!
                         '#': MD_TAG}

However, you can refer to the class MetaDataElement in any yet un-interpreted piece of code, as in

    def method_of_MetaDataElement(self):
        print MetaDataElement.MD_TAG

You even have to refer to MetaDataElement, here, because MD_TAG is not a kind of local variable when method_of_MetaDataElement() is executed (MD_TAG was only defined as a kind of local variable during class construction). Once the class MetaDataElement is created, MD_TAG is simply a class attribute, which is why method_of_MetaDataElement() must refer to it as such.

Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260
  • 1
    The final example could be written with `self.MD_TAG`, which avoids any need to refer to the class name. – Marcin Jul 13 '12 at 03:43
  • @Marcin: `self.MD_TAG` is also a possibility, but it is not equivalent to `MetaDataElement.MD_TAG`, if `MetaDataElement` is subclassed (subclasses might overwrite `MD_TAG`). Both are valid, but which one to choose depends on the situation at hand. – Eric O. Lebigot Jul 13 '12 at 07:48
  • 1
    Honestly, I think it's probably wrong for methods to prevent subclasses from being able to usefully alter class members, which is why I would recommend using `self` unless there is a specific reason to prevent it. – Marcin Jul 13 '12 at 13:14
1

First of all, you're using old-style classes. You should probably use new-style classes, like so:

class MetaDataElement(object):
    ...

Note the (object). Anyway, though, simply remove the MetaDataElement. when referring to the class attributes. This is what it'd look like when that's done:

class MetaDataElement(object):
    (MD_INVALID, MD_CATEGORY, MD_TAG) = range(3)
    mapInitiator2Type = {'!': MD_CATEGORY, 
                         '#': MD_TAG}
icktoofay
  • 126,289
  • 21
  • 250
  • 231