8

Background is I'm getting data from a JSON API where lots of fields are optional and I want most of the fields in a database. When a specific field isn't available I want an empty string ("") written into the database.

Currently I've been doing:

if jsonobject.what_i_look_for:
  dbstring = jsonobject.what_i_look_for
else:
  dbstring = ""

And then inserted dbstring into the database. However I'm getting a lot more of these fields now and I want a much cleaner code rather than a function which consists about 80% of if-statements.

I've found if-shorthands and this shorthand to check if a variable is empty, but both don't seem to work directly as a string. I've tested this using print() in an interactive python 3.5.2 shell:

>>> print(testvar or "")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'testvar' is not defined

>>> print(testvar if testvar else "")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'testvar' is not defined

This: echo (isset($testvar) ? $testvar : ""); is the PHP equivalent of what I seek.

Edit: Since it seems relevant: The object I am trying to process is coming from Telegram's JSON API. I'm using python-telegram-bot as library and this is an example object.

confetti
  • 1,062
  • 2
  • 12
  • 27
  • 2
    `jsonobject.what_i_look_for` is an attribute, not a variable. Is your question about variables or about attributes? Also, `if jsonobject.what_i_look_for:` checks whether the `what_i_look_for_attribute` is set to a truthy value; it does *not* check if that attribute *exists*. So, again, what is your question really? – Aran-Fey Aug 16 '18 at 16:12
  • 1
    Variables don't really exist in Python. There are names which are assigned objects. – Peter Wood Aug 16 '18 at 16:13
  • 1
    [`hasattr`](https://docs.python.org/3/library/functions.html#hasattr) is possibly what you want although it may be better to [ask forgiveness not permission](https://stackoverflow.com/questions/12265451/ask-forgiveness-not-permission-explain) – Peter Wood Aug 16 '18 at 16:13
  • @Aran-Fey Is there a difference in python? I've tried it with both and I get the exact same results, so I figured it wouldn't matter. If it does, I'm looking to see if a JSON object contains an attribute (can be a nested object too). Let me know if I should change my question please. – confetti Aug 16 '18 at 16:14
  • 1
    Yes, attributes and variables are different. – juanpa.arrivillaga Aug 16 '18 at 16:16
  • @confetti: what is `jsonobject`. instance of your own class? a libraries class? a dict? – blue_note Aug 16 '18 at 16:17
  • 2
    If you’re looking for attributes of an object, then you can use `hasattr(obj, name)` to see if it exists, or getattr(obj, name, default)` to get the attribute if it exists or return the default if it doesn’t. But if you find yourself doing `hasattr` or `getattr` for most of your attributes, that’s often a sign that you didn’t want an object full of attributes in the first place, but a dictionary. (Notice that the stdlib json module uses dictionaries.) – abarnert Aug 16 '18 at 16:17
  • I've edited my question. – confetti Aug 16 '18 at 16:17
  • @blue_note To be exact, it's https://python-telegram-bot.readthedocs.io/en/stable/telegram.chat.html this (and similar) object from python-telegram-bot. – confetti Aug 16 '18 at 16:17
  • @abarnert I don't really contol the object I am getting much, I'm just processing different objects coming from telegram's JSON API using `python-telegram-bot`. – confetti Aug 16 '18 at 16:18
  • @PeterWood Mind leaving a full answer? `hasattr` or `getattr` is exactly what I needed, and it works as a shorthand too. – confetti Aug 16 '18 at 16:25

1 Answers1

9

The Pythonic way is to look out for NameError exception that would be raised when the variable is not defined, the name is not bound to any object to be precise.

So, for example:

try:
    foobar
except NameError:
    # Do stuffs
    print('foobar is not defined')
    raise  # raise the original exception again, if you want

Names reside in namespaces e.g. local names reside in locals() (dict) namespace, global names reside in globals() (dict) namespace. You can define a function that takes name string and namespace as an argument to check for the existence, here is a hint passing namespace as a dict and catching KeyError:

In [1213]: def is_defined(name, namespace):
      ...:     try:
      ...:         namespace[name]
      ...:     except KeyError:
      ...:         return False
      ...:     return True
      ...: 

In [1214]: is_defined('spamegg', globals())
Out[1214]: False

In [1215]: spamegg = 10

In [1216]: is_defined('spamegg', globals())
Out[1216]: True

On the other hand, if you are looking to get the value of an atrribute string of an object, getattr is the way to go:

getattr(obj, attr)

For example, the following two are equivalent:

obj.foobar
getattr(obj, 'foobar')

Even you can add a default when the object attribute is missing:

getattr(obj, 'foobar', 'spamegg')

The above will output the value obj.foobar, if foobar is missing it would output spamegg.

You might also be interested in hasattr that returns True/False for an attribute existence check, instead of needing to manually handle AttributeError.

heemayl
  • 39,294
  • 7
  • 70
  • 76
  • Is there a way I can write a function or anything for that? My goal is to get a short and clean code, having a `try` block for every variable I need to check doesn't exactly achieve that. – confetti Aug 16 '18 at 16:15
  • @confetti Names reside in namespaces e.g. local names reside in `locals()` namespace, global names reside in `globals()` namespace. You can define a function that takes namespace as an argument to check for the existence. – heemayl Aug 16 '18 at 16:20
  • `except NameError` is pretty major code smell to me, unless you are in to some pretty arcane meta-programming black-magic, maybe. In any event, reading the op it isn't clear to me if this is even what they need, since they are talking about attributes on objects. – juanpa.arrivillaga Aug 16 '18 at 16:20
  • @confetti why have you found yourself in a situation where you don't know if a name is in scope or not? This doesn't seem related to your question at all, which is about attributes on objects, not whether or not variables are defined.... – juanpa.arrivillaga Aug 16 '18 at 16:22
  • @juanpa.arrivillaga I have edited my OP. I think I worded it wrong at first. I added an example of the exact object I am working with. – confetti Aug 16 '18 at 16:24
  • @heemayl This is a great answer, `getattr` was exactly what I needed though. – confetti Aug 16 '18 at 16:24
  • @confetti No worries. Added a few notes on `getattr` as well. – heemayl Aug 16 '18 at 16:29
  • Thank you a lot, highly appreciated. – confetti Aug 16 '18 at 16:30