I have a class, CameraInterface
, with two properties:
recording
(a boolean)recording_quality
(an enumeration with three possible values)
The user can push hardware buttons (this is a Raspberry Pi project) to select the recording_quality
, but if the camera is already recording
, the hardware will blink/buzz/otherwise indicate that you can’t change the recording_quality
while you are recording.
I would like the CameraInterface
object to enforce this requirement. I don’t want future me to be able to forget this requirement, and accidentally try setting the recording_quality
without first making sure that recording is False
. What is the most Pythonic way to do this?
I’m most familiar with Objective-C, where I might try making the property externally readonly
, and then doing something like this:
- (void)setQuality:(Quality)quality
successHandler:(void (^)(void))successHandler
failureHandler:(void (^)(void))failureHandler
{
if ( self.recording ) {
if ( failureHandler ) {
failureHandler();
}
}
else {
self.quality = quality; // internally writable
if ( successHandler ) {
successHandler();
}
}
}
Update
A clarification on what I am looking for:
- I would like to avoid using exceptions for control flow if possible.
- I would like to build the sometimes-settable nature of
recording_quality
into the programming interface toCameraInterface
, so you don’t have to wait until run-time to find out that you did something wrong. - I already know about Python properties. I’m just looking for the best way to use them (or an alternative).
Update 2
I have been convinced by Martijn Pieters’s answer to use run-time exceptions, and use try/catch when trying to set recording_quality
. Part of what convinced me was trying to implement my Objective-C example in Python. In doing so, I realized that it is really better suited for a statically-typed language. Part of what convinced me was the answer that was linked in Martijn’s answer, which explains in more detail that exceptions are a perfectly normal part of Python control flow.
Here is my Python version of the Objective-C example, above. I leave it here as a warning to others:
import types
class CameraInterface(object):
def __init__(self):
self._recording_quality = 1
self.recording = False
@property
def recording_quality(self):
return self._recording_quality
def set_recording_quality(self, quality, success_handler, failure_handler):
if type(success_handler) is not types.FunctionType:
raise ValueError("You must pass a valid success handler")
if type(failure_handler) is not types.FunctionType:
raise ValueError("You must pass a valid failure handler")
if self.recording is True:
# reject the setting, and call the failure handler
failure_handler()
else:
self._recording_quality = quality
success_handler()
def success():
print "successfully set"
def failure():
print "it was recording, so we couldn't set the quality"
camera = CameraInterface()
print "recording quality starting at {0}".format(camera.recording_quality)
camera.set_recording_quality(3, success, failure)
camera.recording = True
camera.set_recording_quality(2, success, failure)
This prints:
recording quality starting at 1
successfully set
it was recording, so we couldn't set the quality