1

I have a weird problem when trying create a string when using a dictionary value. Basically, I have a function that opens a file, reads a line, and stores the values it finds in that line in a dictionary. Then, it sends those values to an external program. Here is the code:

def createLandscapes(file):

  landscapeParameters = {'FILE': "NULL",
                         'N': "NULL",
                         'K': "NULL",
                         'NUM': "100"}

  for line in file:
    if line == "END LANDSCAPES\n":
      break
    else:
      parameters = line.replace(" ", '').split(",")

      for parameter in parameters:
        parameter = parameter.split("=")
        if parameter[0] not in landscapeParameters:
          malformedFile()
        landscapeParameters[parameter[0]] = parameter[1]

      for key in landscapeParameters:
        if landscapeParameters[key] == "NULL":
          malformedFile()

      # This print statment is for diagnostic purposes
      print("./generateScoreTables {} {} {} {}".format(landscapeParameters['FILE'],
                                                       landscapeParameters['N'],
                                                       landscapeParameters['K'],
                                                       landscapeParameters['NUM']))

      os.system("./generateScoreTables {} {} {} {}".format(landscapeParameters['FILE'],
                                                           landscapeParameters['N'],
                                                           landscapeParameters['K'],
                                                           landscapeParameters['NUM']))

To make this very clear, the function looks for a series of parameter inputs on a single, comma separated line, in the form of

FILE=example, N=20, K=5, NUM=100

It takes those inputs and overrides the default inputs (if specified) in landscapeParameters, and uses the values in landscapeParameters to call an external program.

The strange this is that the string formatting doesn't seem to work correctly when I use the default parameters in landscapeParameters. What I mean by this is that if the function reads the line:

FILE=example, N=20, K=5, NUM=100

Everything works correctly, and the print statement prints:

./generateScoreTables example 20 5 100

However, if the function reads the line:

FILE=example, N=20, K=5

Where I've left NUM out to use the default parameter, I get the following output instead:

./generateScoreTables testland1 15
 0 100
Segmentation fault
sh: 2: 0: not found

It appears that format is not formatting this string correctly, but I don't understand why. Does anyone have any insight into this?

7
  • 4
    Welcome to StackOverflow. Please read and follow the posting guidelines in the help documentation. Minimal, complete, verifiable example applies here. We cannot effectively help you until you post your MCVE code and accurately describe the problem. We should be able to paste your posted code into a text file and reproduce the problem you described. Commented Jun 1, 2017 at 21:07
  • @Prune What exactly would you like me to add? The problem should be readily apparent and easily reproducible from information provided. Commented Jun 1, 2017 at 21:09
  • 1
    Attach the demonstrative input file that produces the error -- perhaps only two lines. Edit your code to the minimal code that will reproduce the error. Perhaps it's no more than a one-line call. Commented Jun 1, 2017 at 21:15
  • 1
    You've been lucky. Someone took pity and answered. @Prune is a long-time member here who is trying to explain the ropes to you. Usually you might find that people will become impatient reading through a lot of verbiage and code like that. Commented Jun 1, 2017 at 21:25
  • 1
    @user1105224: briefly, because it's your job to make it easy for us to start debugging your problem. Your posted code fails to run, even with a constructed input file. Commented Jun 1, 2017 at 21:27

2 Answers 2

2

The problem has already been pointed out to you, but I'm still unable to comment so I'll leave this separate. This would involve reworking your code a little bit.

Once you get to this stage:

parameters = ['FILE=example', 'N=20', 'K=5', 'NUM=100']

# make a list of tuples with [(FILE, default), ('N', 20)...]
pars = [x.split("=") for x in parameters]

Now convert each twople into a Key, value pair in a dictionary dict_of_pars

dict_of_pars = {k: v for k, v in pars}
#dictionary with values for a single line
# {'FILE': 'example', 'N': '20', 'K': '5', 'NUM': '100'}

At this point you will have a dictionary containing all defined parameters for any particular line. If you make a function (that outputs) that holds default values you can send the available arguments for a line using **dict_of_pars in the call

# define output function with default parameters
def output(FILE='example, N='n', K='k', NUM='num'):
      os.system(FILE, N, K, NUM)

Now you can call the function using

  output(**dict_of_pars)  #will unpack the arguments into output function

Made one of these temporary dictionaries for each line in the file, pass it to the output. Hope this helps.

Sign up to request clarification or add additional context in comments.

3 Comments

Sure, I get what you are saying. But do you have any understanding as to why the string formatting doesn't work as described in my question? I tried implementing a new dictionary every loop to prevent possible bogus values (even though this shouldn't be a problem as I was only running the code on one input line) but I still ended up with incorrect string formatting. It seems rather over-complicated to have to write an extra function for nothing else other than formatting string values from a dictionary.
I've just had a good look through and can't find your problem, it prints correctly. The code should run as expected as long as you define the dictionary just after the 'for line in ' statement. Other then this I can't help, sorry.
Thanks for the attempt. I've actually narrowed it down on my own to the point where I'm pretty sure I've run across a bug in Python. It's just not that important for my program and I don't have the time to deal with it right now, so I've just abandoned it and used another implementation.
-1

You're updating the same variable on every loop, so if it reads one line that doesn't have a particular field it will use the value from the last time it read it.

Instead declare an empty dictionary inside the loop and use the .get function to have a default value if the key doesn't exist in the dictionary.

def createLandscapes(file):
    params = ['FILE','N','K','NUM']

    for line in file:
        if line == "END LANDSCAPES\n":
            break
        else:
            landscapeParameters = {}
            parameters = line.replace(" ", '').split(",")

            for parameter in parameters:
                parameter = parameter.split("=")
                if parameter[0] not in params:
                    malformedFile()
                landscapeParameters[parameter[0]] = parameter[1]

                for key in landscapeParameters:
                if landscapeParameters[key] == "NULL":
                    malformedFile()
         os.system("./generateScoreTables {} {} {} {}".format(landscapeParameters.get('FILE',''),
                                                           landscapeParameters.get('N',''),
                                                           landscapeParameters.get('K',''),
                                                           landscapeParameters.get('NUM',100)))

You'll probably need to tweak this a little bit, but it should give you more predictable results.

1 Comment

I just tried this, but I still end up with the same result described.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.