Skip to content Skip to sidebar Skip to footer

Use Class Variables As Instance Vars?

What I would like to do there is declaring class variables, but actually use them as vars of the instance. I have a class Field and a class Thing, like this: class Field(object):

Solution 1:

Every instance of Field (effectively) has a name. Its name is the attribute name (or key) which references it in Thing. Instead of having to look up the key dynamically, you could instantiateFields with the name at the time the class attribute is set in Thing:

classField(object):
    def__init__(self, name):
        self.name = name

    def__set__(self, instance, value):
        instance.__dict__.update({self.name: value})

    def__get__(self, instance, owner):
        if instance isNone:
            return self
        try:
            return instance.__dict__[self.name]
        except KeyError:
            returnNonedefmake_field(*args):
    defwrapper(cls):
        for arg in args:
            setattr(cls, arg, Field(arg))
        return cls
    return wrapper

@make_field('foo')classThing(object):
    pass

And it can be used like this:

new = Thing()

Before new.foo is set, new.foo returns None:

print(new.foo)
# None

After new.foo is set, 'foo' is an instance attribute of new:

new.foo = 'bar'print(new.__dict__)
# {'foo': 'bar'}

You can access the descriptor (the Field instance itself) with Thing.foo:

print(Thing.foo)
# <__main__.Field object at 0xb76cedec>

PS. I'm assuming you have a good reason why

classThing(object):
    foo = None

does not suffice.

Solution 2:

Reread your question and realized I had it wrong:

You don't need to override the default python behavior to do this. For example, you could do the following:

class Thing(object):
    foo = 5

>>>r = Thing()>>>r.foo = 10>>>s = Thing()>>>print Thing.foo
5
>>>print r.foo
10
>>>print s.foo
5

If you want the default to be 'None' for a particular variable, you could just set the class-wide value to be None. That said, you would have to declare it specifically for each variable.

Solution 3:

The easiest way would be to call the attribute something else than the name of the descriptor variable - preferably starting with _ to signal its an implementation detail. That way, you end up with:

def__set__(self, instance, value):
    instance._foo = value

def__get__(self, instance, owner):
    returngetattr(instance, '_foo', None)

The only drawback of this is that you can't determine the name of the key from the one used for the descriptor. If that increased coupling isn't a problem compared to the loop, you could just use a property:

classThing:
    @propertydeffoo(self):
       returngetattr(self, '_foo', None)

    @foo.setterdeffoo(self, value):
       self._foo = value

otherwise, you could pass the name of the variable into the descriptor's __init__, so that you have:

classThing:
    foo = Field('_foo')

Of course, all this assumes that the simplest and most Pythonic way - use a real variable Thing().foo that you set to None in Thing.__init__ - isn't an option for some reason. If that way will work for you, you should prefer it.

Post a Comment for "Use Class Variables As Instance Vars?"