0

Why is this not working? All variables below in print statement evaluate to None.

def assign(data):
    first=middle=last=suffix=None
    sep = ','
    fields = ['last','first','middle','suffix']
    a = data
    for name in fields:
        if a: 
            a, *b = a.split(sep)
            print('intermediate: ', a, b)
            if a:
                locals()[name] = a
                a = None
                if b:
                    a = sep.join(b)
    print('first %s middle %s last %s suffix %s ', first, middle, last, suffix)

if __name__ == "__main__":
    data = 'Jon, Bon, Jovi'
    assign(data)

Edit 1

Evan asked so posting non working code below. Caveat: I fully understand now that there is no good reason to have varying variables ;)

def assign(data):
    first=middle=last=suffix=None
    sep = ','
    fields = ['last','first','middle','suffix']
    a = data
    for name in fields:
        if a: 
            a, *b = a.split(sep)
            print('intermediate: ', a, b)
            if a:
                #locals()[name] = a
                exec('%s = a' % name)
                a = None
                if b:
                    a = sep.join(b)
    print('first %s middle %s last %s suffix %s ', first, middle, last, suffix)

if __name__ == "__main__":
    data = 'Jon, Bon, Jovi'
    assign(data)
  • 2
    You can't use `locals()` that way. The locals of a function are not actually kept in a dictionary, so `locals()` has to synthesize one for you - but there's no transfer in the opposite direction. – jasonharper Apr 24 '19 at 17:51
  • 3
    `locals` is one of those functions which, if you are using, indicates you are probably doing something wrong. – chepner Apr 24 '19 at 17:52
  • 3
    Here, don't define 4 different local names; define a single local `dict` with 4 keys. – chepner Apr 24 '19 at 17:53
  • 1
    Thanks for the responses guys, its greatly appreciated. I want those string-stored variables (in any form) to dynamically get those values. The values are computed correctly, its now a question of assignment. Anyone want to take a stab at fixing this function to make it work? You probably see my intent. – Impostor Syndrome Apr 24 '19 at 17:58
  • Or better yet, `def assign(first=None, middle=None, last=None, suffix=None): ...`, then call with `assign("Jon,Bon,Jovi".split(","))`. – chepner Apr 24 '19 at 17:58
  • 2
    @ImpostorSyndrome yes, **use a dict** don't dynamically create variables. There is almost *never* a good reason to. – juanpa.arrivillaga Apr 24 '19 at 17:58
  • Warning heeded! The original to this post which has been marked duplicate [link](https://stackoverflow.com/questions/8028708/dynamically-set-local-variable) has some good answers. I am either going to return a 4 tuple from the function or use setattr on an object or use a dict. – Impostor Syndrome Apr 24 '19 at 18:57

2 Answers2

0

There is no pythonic way to assign values to local variable names dynamically. If you want this behavior, the simplest solution is to use exec.

If you simply replace the line:

locals()[name] = a

With exec:

exec('%s = a' % name)

Check out the documentation for exec while you are at it.

Evan
  • 2,120
  • 1
  • 15
  • 20
  • 2
    customary warning about exec/eval being potentially dangerous... – Adarsh Chavakula Apr 24 '19 at 18:03
  • 1
    Evan I tried plugging in exec, it didn't work. – Impostor Syndrome Apr 24 '19 at 18:08
  • @ImpostorSyndrome There is no way for anyone to help you without more information. Could you provide a minimal, complete, verifiable example? https://stackoverflow.com/help/mcve – Evan Apr 24 '19 at 18:11
  • @ImpostorSyndrome a good place to start would be fixing the syntax error in your print statement. "print('first %s middle %s last %s suffix %s ' % (first, middle, last, suffix))" – Evan Apr 24 '19 at 18:14
0

locals() returns new dictionary data. It can not be reference of stack memory of "assign" function.

I think you want to make a object easily when you create an instance related of name. How is this code as below:

class Name:
    def __init__ (self, data):
        sep = ','
        fields = ['last', 'first', 'middle', 'suffix']
        data = data.split(sep)
        self.fields = {f:d for f, d in zip(fields, data)}

    def __str__ (self):
        orderedFields = ['first', 'middle', 'last', 'suffix']
        output = ''
        for field in orderedFields:
            output += field+' '+self.fields[field]+' '
        return output

if __name__ == '__main__':
    data = Name('Jon, Bon, Jovi, ')
    print (data)
yaho cho
  • 1,779
  • 1
  • 7
  • 19