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 instantiateField
s 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?"