Use Class Variables As Instance Vars?
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 instantiate Field
s with the name at the time the class attribute is set in Thing
:
class Field(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 is None:
return self
try:
return instance.__dict__[self.name]
except KeyError:
return None
def make_field(*args):
def wrapper(cls):
for arg in args:
setattr(cls, arg, Field(arg))
return cls
return wrapper
@make_field('foo')
class Thing(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
class Thing(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):
return getattr(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:
class Thing:
@property
def foo(self):
return getattr(self, '_foo', None)
@foo.setter
def foo(self, value):
self._foo = value
otherwise, you could pass the name of the variable into the descriptor's __init__
, so that you have:
class Thing:
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?"