Reputation: 26406
Python 3
Data might be a string, bytes or an EmailMessage.
Is this the most effective way to get the bytes out of data?
while True:
try:
# data is a string
f.write(data.encode('utf-8'))
break
except:
pass
try:
# data is an EmailMessage
f.write(data.get_bytes())
break
except:
pass
try:
# data is bytes
f.write(data)
break
except:
pass
else:
self.log.info('Exiting, unknown attachment type')
sys.exit(1)
Upvotes: 2
Views: 233
Reputation: 59681
From wikipedia:
For example, in a non-duck-typed language, one would create a function that requires that the object passed into it be of type Duck, in order to ensure that that function can then use the object's walk and quack methods. In a duck-typed language, the function would take an object of any type and simply call its walk and quack methods, producing a run-time error if they are not defined. Instead of specifying types formally, duck typing practices rely on documentation, clear code, and testing to ensure correct use.
This doesn't mean you can call whatever methods you feel like, and catch an exception if it doesn't exist. You still need to make some effort to only call methods you are sure will be there. Duck-typing is more related to the fact that you don't care what the type of the object is (if you passed it into a function, you don't specify the type as you would in Java), but are still sure that it will respond to a specific method call.
In your case, what I would do is create a wrapper around each of those objects (String, EmailMessage, bytes), with a common method get_data
, where each implementation of get_data is specific to the type of object it wraps around (encode
, get_bytes
etc.). Then your loop would look as follows:
while True:
try:
# data is a string
f.write(data.get_data())
break
except:
pass
Edit: You may also want to see this question which is related to yours: How to handle "duck typing" in Python?
Upvotes: 1
Reputation: 56684
if hasattr(data, "encode"):
f.write(data.encode('utf-8'))
elif hasattr(data, "get_bytes"):
f.write(data.get_bytes())
else:
try:
f.write(data)
except TypeError:
self.log.info('Exiting, unknown attachment type')
sys.exit(1)
Edit:
This is ducktyping - as in "if it quacks like a duck, it is a duck; if it encodes, it is a string".
This is preferred over if isinstance(data, str)
because it is less restrictive; so long as an object knows how to encode itself to bytes, we don't really care if it is actually a string or not.
Exceptions are relatively slow and should be reserved for handling unexpected or unlikely errors.
Upvotes: 7