In a lot of ways, python's a very simple language. It has no special magic that prevents you from being able to set attributes at specific times. If you want that sort of magic, you need to build it yourself.
In a lot of ways, you can begin to think of class instances (and classes themselves) as wrappers around dictionaries. In fact, both classes and instances have a __dict__
attribute:
>>> class Foo(object):
... x = 'bar'
...
>>> Foo.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, 'x': 'bar', '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None})
>>> Foo().__dict__
{}
Why it works.
Setting an attribute on a class instance actually calls the "magic" __setattr__
hook method (if present). If not present, python simply stores the value in the object's dictionary. Since the default is just a dictionary, you can set any value in the dict at any time.
Is it a good idea?
Of course, whether or not it's a good idea boils down to your design philosophy. It's usually best to put some sort of default for the value in the initializer so that the rest of your code doesn't have to guard against AttributeError
that could be raised if you called getX
before setX
was called...
I will say that it is generally not idiomatic to write simple getters and setters in python. In your code, it's most idiomatic just to have an attribute x
:
class MyClass(object):
"""This is my class.
Attributes:
x: the "x" attribute.
"""
def __init__(self, x=None):
self.x = x
Usage looks like:
m = MyClass('foo')
print(m.x)
m.x = 'bar'
print(m.x)
I think that the usual Java argument for setters and getters here is "what if you want to do other actions when you set a value -- Sure, you don't need that now, but maybe you will someday in the future ..."
Actually, Python's got you covered there too. You can always change your simple attribute into a property
without breaking your interface:
class MyClass(object):
def __init__(self, x=None):
self._x = x
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
And now you have all the "advantages" of a java getter/setter pair, but to an outside user, your interface hasn't changed:
m = MyClass('foo')
print(m.x)