warvariuc
warvariuc

Reputation: 59594

Variable not found in the outer class scope

I have this code:

class Attributes(object):
    class __metaclass__(type):
        def __init__(self, cls_name, cls_bases, cls_dict):
            # super(Attributes.__metaclass__, self) # NameError: global name 'Attributes' is not defined
            super(__metaclass__, self).__init__(
                cls_name, cls_bases, cls_dict)

gives

NameError: global name '__metaclass__' is not defined

Why __metaclass__ variable is not found in the outer scope?

Upvotes: 3

Views: 279

Answers (3)

warvariuc
warvariuc

Reputation: 59594

Looks like the answer is this:

Outer scope for a method is not class body, but outer function in which the class is contained or the module.

That's why in the case of

class Test():
    attr_1 = 'smth'
    def a_method(self):
        attr_1  # not visible on this line

attr_1 is not visible inside method Test.a_method

And the solution is to define metaclass at global level:

class AttributesMeta(type):
    def __init__(self, cls_name, cls_bases, cls_dict):
        super(__metaclass__, self).__init__(
            cls_name, cls_bases, cls_dict)

class Attributes(object):
    __metaclass__ = AttributesMeta

Upvotes: 0

Vorsprung
Vorsprung

Reputation: 34307

try this instead

super(Attributes.__metaclass__, self).__init__(cls_name, cls_bases, cls_dict)

Upvotes: 2

Alfe
Alfe

Reputation: 59426

While creating a class, only its name is visible. Its contents does not exist yet until the class is finished being created. The parts inside the class, therefore, cannot access any fields of the class during creation. So you will need to use fully qualified names to denote that you want to access fields of the class

You are currently creating a class SimpleModel and while doing so you are creating a class Attributes and while doing so a class __metaclass__. Since while you do this, the class SimpleModel isn't existing yet, the method __init__ is not yet part of anything existing. It first gets created and then, later, will be made part of the class __metaclass__. Hence it cannot know the identifier __metaclass__. And since __metaclass__ also never becomes a global, when called, this identifier cannot be known.

That's the reason why you have no __metaclass__ in your scope at this point, but when later __init__ gets called, only a SimpleModel is available via the global scope, so you can base your name on it: SimpleModel.Attributes.__metaclass__.

Upvotes: 1

Related Questions