I want to write a suite of methods that act as getters when passed zero arguments and as setters when passed a single argument. I have two two reasonable implementations, shown below. Is one better than the other, or is there perhaps an even better way?
class Thing(object):
def __init__(self):
self._size = 0
def sizeA(self, *args):
if not args:
return self._size
self._size = args[0]
return self
UNIQUE_ID = []
def sizeB(self, arg=UNIQUE_ID):
if arg is self.UNIQUE_ID:
return self._size
self._size = arg
return self
A couple of comments:
sizeA()
benchmarks faster than sizeB()
, but doesn't give me argument count checking. sizeB()
works, but it depends on UNIQUE_ID
being invariant, and I wonder if there are circumstances (e.g. pickling) that would cause it to break.
P.S.: Though I'm currently developing in python-2.7, I'm open to python-3.x specific answers as appropriate.
1 Answer 1
A sentinel and a defaulted arg is a good way to do it. I would use an arbitrary object though, not a list (preference, and this way someone won't go about fiddling with it).
class A(object):
_DEFAULT = object()
def __init__(self):
self._size = 0
def sizeC(self, arg=_DEFAULT):
if arg is not DEFAULT:
self._size = arg
return self._size
And pickle will handle it fine (it also handles it fine with a list, change _DEAFULT
to be []
and change it to print id(y._DEFAULT)
).
a = A()
a.sizeC(10)
x = pickle.dumps(a)
y = pickle.loads(x)
print y._DEFAULT
print y.sizeC()
print y.sizeC(20)
print y.sizeC()
print y._DEFAULT
print a._DEFAULT
gives
andy@batman:~$ p tmp.py
<object object at 0x7ff952223090>
10
20
20
<object object at 0x7ff952223090>
<object object at 0x7ff952223090>
I can't think of a situation where this would cause issue, and is an accepted pattern as far as I'm aware (I don't have any citations to hand.)
Out of curiosity, what is the difference in the benchmark between the two options?
Thing().size(30).color('red')
etc..., and despite grumblings to the contrary I think fluency is a reasonable approach for my application.self
. See stackoverflow.com/q/21785689/102937if len(args):
be the most robust?*args
argument can only ever be a tuple, and tuples are only evaluated as False in a boolean context if it has zero arguments, so there is no difference in robustness.