0

I have a class that starts as follows:

from collections import namedtuple

class Parser:
    Rule = namedtuple('Rule', ['lhs', 'rhs', 'dot_pos', 'start_pos', 'end_pos'])

    # __init__ ...

Since PyCharm detected all my tuple element namings correctly by giving me proper suggestions, I assumed I did it the right way so far, creating a little Rule class with the syntax shown above.

Now, I have a method within my Parser class that takes a Rule parameter:

def add(self, dot_rule: Rule):
    print(dot_rule.end_pos)
    # ...

Unfortunately, following error appears as soon as I try to call an element of dot_rule like end_pos:

AttributeError: 'tuple' object has no attribute 'end_pos'

What is it that I misunderstood when using namedtuple?

Edit: I call the method add the following way with lhs, rhs, and pos being some values calculated beforehand:

self.add((lhs, rhs, 0, pos, pos))

I thought since namedtuple is said to be backward-compatible with tuple this would be the correct syntax. Apparently, the parameter is now seen as a plain tuple instead of a Rule. What can I do differently here?

Edit 2: Traceback message:

Traceback (most recent call last):
  File "...\earley.py", line 19, in <module>
    main()
  File "...\earley.py", line 14, in main
    parser = Parser(grammar, lexicon, sentence)
  File "...\parser.py", line 21, in __init__
    self.parse(sentence)
  File "...\parser.py", line 56, in parse
    self.predict('S', i)
  File "...\parser.py", line 41, in predict
    self.add((lhs, rhs, 0, pos, pos))  # (X -> .α, i, i)
  File "...\parser.py", line 24, in add
    print(dot_rule.end_pos)
AttributeError: 'tuple' object has no attribute 'end_pos'
TiMauzi
  • 190
  • 1
  • 3
  • 16
  • 7
    You apparently passed something to `.add()` that is a plain tuple, rather than a `Rule`. You haven't shown us the code where the method is actually called, and that parameter to it is created. (The full traceback message would have shown exactly where that was, but you didn't show that either.) – jasonharper May 22 '22 at 19:32
  • 2
    Type annotating the parameter doesn't automatically make it a namedtuple when a normal tuple is passed – Lecdi May 22 '22 at 19:35
  • @jasonharper Thanks for the suggestion, I added the moment `.add()` is called. And you are right of course, I obviously passed a plain `tuple`. What can I do instead here? – TiMauzi May 22 '22 at 19:38
  • @jasonharper Added the traceback message, too. Hope the question is more informative now. – TiMauzi May 22 '22 at 19:41

1 Answers1

1

You can try this: essentially you were passing it a class tuple instead of the namedtuple called Rule. See:

Instead of self.add((lhs, rhs, 0, pos, pos))

Use self.add(Parser.Rule(lhs, rhs, 0, pos, pos))

mj_codec
  • 170
  • 8
  • 1
    Thank you, this worked perfectly. I think I misunderstood the idea of the backwards compatibility of `namedtuple`. Both `Parser.Rule(lhs, rhs, 0, pos, pos)` and `self.Rule(lhs, rhs, 0, pos, pos)` seem to work equally well, by the way. Would be interesting to know if there is any real difference between these variations. – TiMauzi May 22 '22 at 19:51