Prob. Code Downloaded for Programming the Semantic Web (python code)

Bruce Whealton futurewavewebdevelopment at gmail.com
Mon Jul 28 13:07:27 CEST 2014


On Friday, July 25, 2014 11:25:15 PM UTC-4, Chris Angelico wrote:
> On Sat, Jul 26, 2014 at 10:06 AM, Bruce Whealton
> 
Chris,
    In response to your comments below, I'm comfortable changing this to use python 3.
> 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.
> 
 
> 
> 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:
> 

OK, that makes sense. So, I cut out the "Alternatively... " suggestion you made.
> 
> 
> def add(self, args):
> 
>     sub, pred, obj = args
> 
>     # rest of code as before
> 
> 
> 
> Preferably with a better name than 'args'.

Yes, I could call it triples. 
> 
> >         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)]
> 
> 
This is helpful and makes sense... clarifies it for me.
> 
> 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))
>
I didn't see the above in the code... Is this something I would need to add and if so, where? 
> 
> 
>    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.
> 
So far it is just from the book, and just serves as an example...  It is also a few years old, having been published in 2009.
> 
> 
> 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.
> 
I would have to get a better understanding of this.  
> 
> 
> (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.

I was curious about why the binary flag was being used.  It just made no sense to me.
> 
> 
> 
> 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:

I would like to see this in python 3 format.
> 
>     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

Thanks,
Bruce




More information about the Python-list mailing list