Вложенные аргументы не компилируются

Я пытаюсь скомпилировать мой код в модуль Python 3. Он работает нормально, когда я выбираю "Запустить модуль" в IDLE, но я получаю следующую синтаксическую ошибку при попытке создать дистрибутив:

File "/usr/local/lib/python3.2/dist-packages/simpletriple.py", line 9
    def add(self, (sub, pred, obj)):
                  ^
SyntaxError: invalid syntax

Может кто-нибудь помочь указать, что не так с синтаксисом? Вот полный код:

import csv

class SimpleGraph:
    def __init__(self):
        self._spo = {}
        self._pos = {}
        self._osp = {}

    def add(self, (sub, pred, obj)):
        """
        Adds a triple to the graph.
        """
        self._addToIndex(self._spo, sub, pred, obj)
        self._addToIndex(self._pos, pred, obj, sub)
        self._addToIndex(self._osp, obj, sub, pred)

    def _addToIndex(self, index, a, b, c):
        """
        Adds a triple to a specified index.
        """
        if a not in index: index[a] = {b:set([c])}
        else:
            if b not in index[a]: index[a][b] = set([c])
            else: index[a][b].add(c)

    def remove(self, (sub, pred, obj)):
        """
        Remove a triple pattern from the graph.
        """
        triples = list(self.triples((sub, pred, obj)))
        for (delSub, delPred, delObj) in triples:
            self._removeFromIndex(self._spo, delSub, delPred, delObj)
            self._removeFromIndex(self._pos, delPred, delObj, delSub)
            self._removeFromIndex(self._osp, delObj, delSub, delPred)

    def _removeFromIndex(self, index, a, b, c):
        """
        Removes a triple from an index and clears up empty indermediate structures.
        """
        try:
            bs = index[a]
            cset = bs[b]
            cset.remove(c)
            if len(cset) == 0: del bs[b]
            if len(bs) == 0: del index[a]
        # KeyErrors occur if a term was missing, which means that it wasn't a valid delete:
        except KeyError:
            pass

    def triples(self, (sub, pred, obj)):
        """
        Generator over the triple store.
        Returns triples that match the given triple pattern. 
        """
        # check which terms are present in order to use the correct index:
        try:
            if sub != None: 
                if pred != None:
                    # sub pred obj
                    if obj != None:
                        if obj in self._spo[sub][pred]: yield (sub, pred, obj)
                    # sub pred None
                    else:
                        for retObj in self._spo[sub][pred]: yield (sub, pred, retObj)
                else:
                    # sub None obj
                    if obj != None:
                        for retPred in self._osp[obj][sub]: yield (sub, retPred, obj)
                    # sub None None
                    else:
                        for retPred, objSet in self._spo[sub].items():
                            for retObj in objSet:
                                yield (sub, retPred, retObj)
            else:
                if pred != None:
                    # None pred obj
                    if obj != None:
                        for retSub in self._pos[pred][obj]:
                            yield (retSub, pred, obj)
                    # None pred None
                    else:
                        for retObj, subSet in self._pos[pred].items():
                            for retSub in subSet:
                                yield (retSub, pred, retObj)
                else:
                    # None None obj
                    if obj != None:
                        for retSub, predSet in self._osp[obj].items():
                            for retPred in predSet:
                                yield (retSub, retPred, obj)
                    # None None None
                    else:
                        for retSub, predSet in self._spo.items():
                            for retPred, objSet in predSet.items():
                                for retObj in objSet:
                                    yield (retSub, retPred, retObj)
        # KeyErrors occur if a query term wasn't in the index, so we yield nothing:
        except KeyError:
            pass

    def value(self, sub=None, pred=None, obj=None):
        for retSub, retPred, retObj in self.triples((sub, pred, obj)):
            if sub is None: return retSub
            if pred is None: return retPred
            if obj is None: return retObj
            break
        return None

    def load(self, filename):
        f = open(filename, "rb")
        reader = csv.reader(f)
        for sub, pred, obj in reader:
            sub = unicode(sub, "UTF-8")
            pred = unicode(pred, "UTF-8")
            obj = unicode(obj, "UTF-8")
            self.add((sub, pred, obj))
        f.close()

    def save(self, filename):
        f = open(filename, "wb")
        writer = csv.writer(f)
        for sub, pred, obj in self.triples((None, None, None)):
            writer.writerow([sub.encode("UTF-8"), pred.encode("UTF-8"), obj.encode("UTF-8")])
        f.close()

if __name__ == "__main__":
    g = SimpleGraph()
    g.add(("blade_runner", "name", "Blade Runner"))
    g.add(("blade_runner", "name", "Blade Runner"))
    g.add(("blade_runner", "release_date", "June 25, 1982"))
    g.add(("blade_runner", "directed_by", "Ridley Scott"))

    print list(g.triples((None, None, None)))
    print list(g.triples(("blade_runner", None, None)))
    print list(g.triples(("blade_runner", "name", None)))
    print list(g.triples(("blade_runner", "name", "Blade Runner")))
    print list(g.triples(("blade_runner", None, "Blade Runner")))
    print list(g.triples((None, "name", "Blade Runner")))
    print list(g.triples((None, None, "Blade Runner")))

    print list(g.triples(("foo", "name", "Blade Runner")))
    print list(g.triples(("blade_runner", "foo", "Blade Runner")))
    print list(g.triples(("blade_runner", "name", "foo")))
 Tadeck15 мая 2012 г., 21:15
Пожалуйста, поместите свой код здесь, на pastebin или где-то еще, чтобы его не нужно было загружать.
 Ben Hoyt15 мая 2012 г., 21:18
@ Tadeck: на самом деле, ему достаточно контекста с трассировкой, так что, вероятно, нет необходимости.

Ответы на вопрос(1)

Решение Вопроса

PEP 3113 объясняет, почему эта функция, «распаковка параметров кортежа», была удалена в Python 3. Также объясняется, как переносить код, который их использует. В этом случае вам нужно изменить функцию, например:

    self._addToIndex(self._spo, sub, pred, obj)
    self._addToIndex(self._pos, pred, obj, sub)
    self._addToIndex(self._osp, obj, sub, pred)

в версию, которая передает кортеж как один параметр и распаковывает его вручную:

def add(self, sub_pred_obj):
    sub, pred, obj = sub_pred_obj
    self._addToIndex(self._spo, sub, pred, obj)
    self._addToIndex(self._pos, pred, obj, sub)
    self._addToIndex(self._osp, obj, sub, pred)

Дляlambda функция, вы не можете использовать назначение для распаковки. Лучшее решение обычно не распаковывать. Например, измените это:

lambda (x, y): (y, x)

… к этому

lambda xy: (xy[1], xy[0])

Для сложных функций это может показаться уродливым, но для сложных функций вы, вероятно, захотитеdef в любом случае.

Стоит отметить, что ваш код проходит через2to3, modernize, илиfuturize найдет эту проблему в обоихdef а такжеlambda, и предложите именно эти решения:

$ echo 'lambda (x,y): (y,x)' | 2to3 -
--- <stdin> (original)
+++ <stdin> (refactored)
@@ -1 +1 @@
-lambda (x,y): (y,x)
+lambda x_y: (x_y[1],x_y[0])

$ echo -e 'def foo((x,y)):\n    return (y,x)\n' | 2to3 -
--- <stdin> (original)
+++ <stdin> (refactored)
@@ -1 +1 @@
-def foo((x,y)):
+def foo(xxx_todo_changeme):
+    (x,y) = xxx_todo_changeme

Если вы пытаетесь портировать код Python 2.x на 3.x (или на код с двумя версиями) и не знаете оба языка, вы почти наверняка захотите использовать один из этих инструментов - или плагин IDE, который переносит им - чтобы помочь. (Хотя вы можете не использовать его вывод как есть.)

 Ben Hoyt11 сент. 2018 г., 20:55
@ abarnert Извини, ты прав! Я поспешил и неправильно прочитал ваш первый абзац как «вы не можете использовать распаковку кортежей в лямбдах». Отменено, и спасибо!
 Ben Hoyt10 сент. 2018 г., 18:59
@ abarnert К вашему сведению я откатил вашу ревизию, потому что она неверна. В Python 2.x распаковка кортежей прекрасно работает в лямбдах (как и в не лямбдах), см. Здесь: Gist.github.com / benhoyt / e211858be3786a02b0f93153428effea
 Pynchia14 окт. 2015 г., 11:17
Как ты кодируешь, когда функция лямбда? Используйтеt[0] t[1] а такжеt[2]?
 oivemaria04 мая 2015 г., 21:39
момента публикации этой книги (на которую ссылается OP) многое изменилось в кодировке. Я работаю над этим кодом, столкнулся с той же проблемой и наткнулся на ваш пост. Есть ли ресурс, к которому я могу обратиться, чтобы получить больше разъяснений о том, как изменился код, так как я перебираю все коды в книге (в конце концов)
 abarnert10 сент. 2018 г., 20:45
@ BenHoyt Конечно, он отлично работает в 2.x. Но вопрос в том, как перенести этот код в 3.x, где он не работает, и в этом весь смысл вашего ответа. И ваш ответ отлично работает дляdef, но не работает дляlambda, потому что это зависит от оператора присваивания. Пожалуйста, перечитайте мои изменения (и вопрос, и ваш ответ) более внимательно; Я не думаю, что там что-то не так.

Ваш ответ на вопрос