1

Hello I'm new to python programming and wasn't sure how to use getopt. So, since I thought python was a pretty straight forward language, I decided to write my own getopt function. It goes like this:

string = "a b -c -d"
list = string.split()

def get_short_opts(args):
   opts = ""
   for word in args:
      print("Word = " + word)
      if word[0] == '-' and word[1] != '-':
         opts += word[1:]   #to remove the '-'
         args.remove(word)

   print("Opts = " + opts)
   print("Args = " + str(args))

   return opts

print(get_short_opts(list))

Basically, this function returns all characters located after a "-" character. It works when I use multiple options at one time and with only one "-" and if I do something like

["-a", "arg", "-b"] 

But when I try to pass multiple options immediately after each other, it doesn't work. The main code above is an example of when it does not work. Could you explain why it only works sometimes and not other times? Any help would be appreciated. Thank you!

  • Something worth mentioning is [`argparse`](https://docs.python.org/2/howto/argparse.html). It's fairly easy to use and figures out the basic error messages and descriptions if the user gives the wrong syntax. – e0k Jan 24 '16 at 23:25
  • I'm not so worried about how to use it or how it works I just want to figure out what is wrong with my code. – ForTheReallys Jan 24 '16 at 23:33

1 Answers1

2

Problem

The problem is that you can't delete from the list while you're iterating through it.

See this question, especially this answer quoting the official Python tutorial:

If you need to modify the sequence you are iterating over while inside the loop (for example to duplicate selected items), it is recommended that you first make a copy. Iterating over a sequence does not implicitly make a copy.

(C++ people call this "iterator invalidation," I don't know the pythonic term for it, if there is one.)

Solution

Iterate over a copy of the args and remove from the original:

string = "a b -c -d"
list = string.split()

def get_short_opts(args):
   opts = []
   for word in args[:]:
      print("Word = " + word)
      if word[0] == '-' and word[1] != '-':
         opts.append(word[1:])   #to remove the '-'
         args.remove(word)

   print("Opts = " + str(opts))
   print("Args = " + str(args))

   return opts

print(get_short_opts(list))

The args[:] notation is a slice from the beginning to the end of args, in other words, the whole thing. But the slice is a copy, and not the original. You can then remove from the original args as you did before, without affecting the iteration sequence.

Also notice that I have changed your opts from a string to a list. It just seemed to make sense that way. You can iterate through it, count the members, etc. You can put it back the way you had it (a string with each option concatenated) if you want.

Community
  • 1
  • 1
e0k
  • 6,961
  • 2
  • 23
  • 30