On Sat, Jul 26, 2014 at 10:06 AM, Bruce Whealton <futurewavewebdevelopm...@gmail.com> wrote: > OK, Eclipse with PyDev doesn't like this first line, with the function: > def add(self, (sub, pred, obj)):
As others have said, this is something that changed in Python 3. So you have two parts to the problem: firstly, your code is bound to Python 2 by a triviality, and secondly, Eclipse is complaining about it. One solution would be to teach Eclipse that this is legal, or for you to just ignore its complaints. If your code works in Python 2.7, then there's no big problem. You could try telling Eclipse that you're using Python 2 (maybe by putting a shebang at the top of your script), but that may not work; in any case, that's just an issue with the editor. But a better solution, IMO, would be to avoid that implicit tuple unpacking. It's not a particularly clear feature, and I'm not sorry it's gone from Py3. The simplest way to change it is to just move it into the body: def add(self, args): sub, pred, obj = args # rest of code as before Preferably with a better name than 'args'. Alternatively, change the places that call add() and have them provide four separate arguments, in which case the signature would simply be: def add(self, sub, pred, obj): like you'd expect. > triples = list(self.triples((sub, pred, obj))) > > Are the two sets parentheses needed after self.triples? That syntax is > confusing to me. It seems that it should be > triples = list(self.triples(sub, pred, obj)) No, that's correct. The extra parens force that triple to be a single tuple of three items, rather than three separate arguments. Here's a simpler example: >>> lst = [] >>> lst.append(1,2,3) Traceback (most recent call last): File "<pyshell#25>", line 1, in <module> lst.append(1,2,3) TypeError: append() takes exactly one argument (3 given) >>> lst.append((1,2,3)) >>> addme = 4,5,6 >>> lst.append(addme) >>> lst [(1, 2, 3), (4, 5, 6)] The list append method wants one argument, and appends that argument to the list. Syntactically, the comma has multiple meanings; when I assign 4,5,6 to a single name, it makes a tuple, but in a function call, it separates args in the list. I don't see why the triples() function should be given a single argument, though; all it does is immediately unpack it. It'd be better to just remove the parens and have separate args: triples = list(self.triples(sub, pred, obj)) def triples(self, sub, pred, obj): While I'm looking at the code, a few other comments. I don't know how much of this is your code and how much came straight from the book, but either way, don't take this as criticism, but just as suggestions for ways to get more out of Python. Inside remove(), you call a generator (triples() uses yield to return multiple values), then construct a list, and then iterate exactly once over that list. Much more efficient and clean to iterate directly over what triples() returns, as in save(); that's what generators are good for. In triples(), the code is deeply nested and repetitive. I don't know if there's a way to truly solve that, but I would be inclined to flatten it out a bit; maybe check for just one presence, to pick your index, and then merge some of the code that iterates over an index. Not sure though. (Also: It's conventional to use "is not None" rather than "!= None" to test for singletons. It's possible for something to be equal to None without actually being None.) I would recommend moving to Python 3, if you can. Among other benefits, the Py3 csv module allows you to open a text file rather than opening a binary file and manually encoding/decoding all the parts separately. Alternatively, if you don't need this to be saving and loading another program's files, you could simply use a different file format, which would remove the restrictions (and messes) of the CSV structure. Instead of explicitly putting "f.close()" at the end of your load and save methods, check out the 'with' statement. It'll guarantee that the file's closed even if you leave early, get an exception, or anything like that. Also, I'd tend to use the .decode() and .encode() methods, rather than the constructors. So here's how I'd write a Py2 load: def load(self, filename): with open(filename, "rb") as f: for sub, pred, obj in csv.reader(f): self.add((sub.decode("UTF-8"), pred.decode("UTF-8"), obj.decode("UTF-8"))) (You might want to break that back out into three more lines, but this parallels save(). If you break this one, you probably want to break save() too.) Hope that helps! ChrisA -- https://mail.python.org/mailman/listinfo/python-list