views:

109

answers:

5

Hey, I'm fairly new to python I have this piece of code which stores the birth info to the datastore in Google App Engine. The code works but is it the correct way to do it? Is there a simpler way to do it, to make sure that the key exists before storing it in datastore?

def store_birthinfo(self, user, birthday):
  """
      Store birthinfo
  """

  name = ''
  date = ''
  place = ''
  country = ''

  for key in birthday.keys():
    if key == 'name':
      name = birthday['name']
    elif key == 'date':
      date = birthday['date']
    elif key == 'place':
      place = birthday['place']
    elif key == 'country':
      country = birthday['country']


  birthinfo = BirthInfo(user    = user,
                        date    = date,
                        place   = place,
                        country = country)
  birthinfo.put()
+2  A: 
def store_birthinfo(self, user, birthday):
  """
      Store birthinfo
  """

  birthinfo = BirthInfo(user=user, **birthday)
  birthinfo.put()

see the docs on unpacking argument lists.

ʞɔıu
Thanks. If one of the key doesn't exist, will it set that key's value to an empty string or None?
nico
It won't set the value at all, the keyword will be missing from the BirthInfo constructor. I'm not sure what the effect of that will be.
Ned Batchelder
It should be whatever the default is for that column, which is probably None unless you've given it a different default
ʞɔıu
If `birthday` has an extra field, this will bomb with a `TypeError`. This is only a problem if you're worried about `birthday` having extra fields.
jcdyer
+1  A: 

ʞɔıu's answer is the shortest, though it has slightly different semantics than yours, in that yours will provide an explicit empty string argument if the key is missing from the dictionary, while ʞɔıu's will omit the keyword argument altogether.

For the sake of completeness, there's a simpler way to do what you were doing without going all the way to **:

def store_birthinfo(self, user, birthday):
  """
      Store birthinfo
  """

  birthinfo = BirthInfo(user    = user,
                        date    = birthday.get('date', ''),
                        place   = birthday.get('place', ''),
                        country = birthday.get('country', ''))
  birthinfo.put()
Ned Batchelder
A: 

A problem might be if your variable 'birthday' contains keys that the class BirthInfo doesn't expect. A more solid solution might be this which also gives you the clear insight into if blanks ones become None or empty string:

def store_birthinfo(self, user, birthday):
  data = dict(name='', date='', place='', country='')
  for key in [x for x in birthday.keys() if x in data]:
      data[key] = birthday[key]

  BirthInfo(user=user, **data).put()
Peter Bengtsson
I would prefer `data.update(birthday)`, as it is easier and more readable than that for loop.
catchmeifyoutry
data.update has a very different effect though. It will add new fields where they don't exist in data. This loop will only assign to keys that have been defined in data.
jcdyer
+1  A: 

You can create a default dictionary and then update the target dictionary as in

def store_birthinfo(self, user, birthday):
  """Store birthinfo"""
  birth_defaults = { 'name' : '',
                     'date' : '',
                     'place' : '',
                     'country' : ''}

  birth_defaults.update(birthday)
  birthinfo = BirthInfo(**birth_defaults)
  birthinfo.put()

In this way you will always have all the params set.

fabrizioM
A: 

Building on Peter Bengtsson's post, you could also define the list of relevant keys, and leave data as an empty {} until the loop populates it.

def store_birthinfo(self, user, birthday):
    data = {}
    for key in 'date', 'place', 'country':
        data[key] = birthday.get(key, '')
    BirthInfo(user=user, **data).put()

I believe this is the most terse and extensible way to specify which keys to use from the birthday dict. With a little more verbosity, you could probably write a function to introspect BirthInfo for the arguments it can accept.

jcdyer
Re: most terse, try `data = {(key, birthday.get(key, '')) for key in ('date', 'place', 'country')}`
hughdbrown
Granted. I should have taken into account the wise words of Ted the Bellhop: "The less one makes declarative statements, the less one is apt to look foolish in retrospect."
jcdyer
Didn't run my owen code. I think that should be `dict(...)`.
hughdbrown
I let it slide thinking you were using the dictionary generator syntax from python 3. But that's slightly different too, I think. That would be {key: birthday.get(key, '') for key in ('date', 'place', 'country')} What you did would be a set generator, creating a set of tuples.
jcdyer