#python
Вопрос:
Я перепечатал код из книги learn python hard way ex48, и я получаю имя ошибки «parse_subj» не определено. Я поискал в гугле обычные решения для такого рода ошибок, но этого не произошло.
user_sentence = [('verb', 'run'), ('direction', 'north')]
class Sentence(object):
def __init_(self, subj, verb, obj):
self.subject = subj[1]
self.verb = verb[1]
self.object = obj[1]
def peek(word_list):
if word_list:
word = word_list[0]
return word
else:
return None
#took the word and get out from list - if it is expecting type return word, if not - None
def match(word_list, expecting):
if word_list:
word = word_list.pop(0)
if word[0] == expecting:
return word
else:
return None
else:
return None
def skip(word_list, word_type):
while peek(word_list) == word_type:
match(word_list, word_type)
def parse_verb(word_list):
skip(word_list, 'stop_words')
next_word = peek(word_list)
if next_word == 'verb':
return match(word_list, 'verb')
else:
raise ParserError('Expected a verb')
def parse_obj(word_list):
skip(word_list, 'stop_words')
next_word = peek(word_list)
if next_word == 'nouns':
return match(word_list, 'nouns')
elif next_word == 'direction':
return match(word_list, 'direction')
else:
raise ParserError('Expected an obj')
def parse_subj(word_list):
skip(word_list, 'stop_words')
next_word = peek(word_list)
if next_word == 'pron':
return match(word_list, 'pron')
elif next_word == 'verb':
return ('noun', 'player')
else:
raise ParserError('Expected an subj')
def parse_sentence(word_list):
subj = parse_subj(word_list)
verb = parse_verb(word_list)
obj = parse_obj(word_list)
return Sentence(subj, verb, obj)
example = Sentence.parse_sentence(user_sentence)
print(example)
Я попытался поиграть с самим собой и вызвать класс предложения в другой переменной, но это не сработало. Я даже скопировал код из pdf-книги, и он все равно не работал
Комментарии:
1. Вам нужно перепроверить код, с которого вы скопировали. Если предполагается, что эти функции являются методами класса, все они должны иметь
self
в качестве первого параметра, и ваш вызов наparse_subj(word_list)
самом деле должен бытьself.parse_subj(word_list)
. Хотя это не единственная проблема с кодом.2. Оказалось, что в исходном коде все функции находились вне предложения класса. Вот почему все предлагаемые решения для исправления моего кода указывали на необходимость самостоятельного аргументирования
Ответ №1:
В коде Python существует так называемая Глобальная область. Это относится ко всем функциям и переменным, которые не находятся внутри какого-либо класса или какой-либо функции.
Когда вы просто говорите parse_subj
, интерпретатор будет искать этот метод в глобальной области. Но ваш метод на самом деле находится внутри класса Sentence
. Вам нужно явно указать интерпретатору, который parse_subj
находится внутри Sentence
класса, а не в глобальной области. Вы делаете это либо , говоря self.parse_subj
, где self
находится первый параметр parse_subj
метода, представляющий экземпляр Sentence
созданного вами класса. Либо это, либо вы используете то, что известно как неограниченный вызов, где вы явно указываете Sentence.parse_subj
, чтобы сообщить интерпретатору, где находится метод.
Я не советую использовать второй подход, но он выглядит логичным, поскольку ни у одного из методов вашего класса даже нет self
параметра, за исключением инициализатора вверху. Вам нужно будет выполнить добавление всего кода Sentence.
перед каждым вызовом метода в Sentence
классе.
Ответ №2:
Во-первых, word_list-это не список, как вы предполагали, в большинстве ваших методов это экземпляр example
Во-вторых, поскольку методы, которые вы пытаетесь вызвать, являются частью этого экземпляра, вот как вы должны их вызывать: self.word_list
и вот как должны быть ваши параметры: self, word_list
в правильном порядке
В-третьих, вместо example = Sentence.parse_sentence(user_sentence)
того, чтобы делать
example = Sentence("example_subj", "example_verb", "example_obj")
example.parse_sentence(user_sentence)
в конце концов, вот окончательный код:
user_sentence = [('verb', 'run'), ('direction', 'north')]
class Sentence(object):
def __init_(self, subj, verb, obj):
self.subject = subj[1]
self.verb = verb[1]
self.object = obj[1]
def peek(self, word_list):
if word_list:
word = word_list[0]
return word
else:
return None
#took the word and get out from list - if it is expecting type return word, if not - None
def match(self, word_list, expecting):
if word_list:
word = word_list.pop(0)
if word[0] == expecting:
return word
else:
return None
else:
return None
def skip(self, word_list, word_type):
while self.peek(word_list) == word_type:
self.match(word_list, word_type)
def parse_verb(self, word_list):
self.skip(word_list, 'stop_words')
next_word = self.peek(word_list)
if next_word == 'verb':
return self.match(word_list, 'verb')
else:
raise ParserError('Expected a verb')
def parse_obj(self, word_list):
self.skip(word_list, 'stop_words')
next_word = self.peek(word_list)
if next_word == 'nouns':
return match(word_list, 'nouns')
elif next_word == 'direction':
return self.match(word_list, 'direction')
else:
raise ParserError('Expected an obj')
def parse_subj(self, word_list):
self.skip(word_list, 'stop_words')
next_word = self.peek(word_list)
if next_word == 'pron':
return self.match(word_list, 'pron')
elif next_word == 'verb':
return ('noun', 'player')
else:
raise ParserError('Expected an subj')
def parse_sentence(self, word_list):
subj = self.parse_subj(word_list)
verb = self.parse_verb(word_list)
obj = self.parse_obj(word_list)
return Sentence(subj, verb, obj)
example = Sentence.parse_sentence(user_sentence)
print(example)
Ответ №3:
Быстрый ответ на ваш вопрос заключается в том, что при обращении к методу parse_subj
внутри класса, вы должны вызвать его в зависимости от его типа, например, если это метод экземпляра, вам нужно определить экземпляр класса, прежде чем обращаться к этому методу, при условии, что данный метод должен быть написан, чтобы принять self
(относится к экземпляру объекта) в качестве первого аргумента.
Для меня фактический ответ на ваш вопрос-пропустить этот класс предложений, так как он очень сложный. Это все равно что научиться умножать, не понимая, как работает сложение. Вы должны понимать, как работают эти 3 типа методов в классе:
- Статический метод — оформленный
@staticmethod
, может быть вызван с помощью самого класса или экземпляра класса - Метод класса — оформлен
@classmethod
, принимаетcls
в качестве первого аргумента, где cls ссылается на сам класс, может быть вызван с использованием самого класса или экземпляра класса - Метод экземпляра — без декоратора, принимает
self
в качестве первого аргумента, где self ссылается на объект класса, может быть вызван только с использованием экземпляра класса
Возможно, вас заинтересует приведенный ниже код, который просто выводит текст.
class Sample:
outer_var = "my outer var"
def __init__(self, var):
print(f"__init__ var = {var}")
self.inner_var = var
@staticmethod
def this_is_static_method(var3):
print("==========")
print(f"this_is_static_method")
try: print(f"tSample.outer_var = {Sample.outer_var}")
except Exception: print("tERROR!!! Cannot access Sample.outer_var")
try: print(f"tSample.inner_var = {Sample.inner_var}")
except Exception: print("tERROR!!! Cannot access Sample.inner_var")
print(f"tvar3 {var3}")
@classmethod
def this_is_class_method(cls, var3):
print("==========")
print(f"this_is_class_method type(cls) {type(cls)} cls {cls}")
try: print(f"tcls.outer_var = {cls.outer_var}")
except Exception: print("tERROR!!! Cannot access cls.outer_var")
try: print(f"tcls.inner_var = {cls.inner_var}")
except Exception: print("tERROR!!! Cannot access cls.inner_var")
print(f"tvar3 {var3}")
return cls(var3)
def this_is_instance_method(self, var3):
print("==========")
print(f"this_is_instance_method type(self) {type(self)} self {self}")
try: print(f"tself.outer_var = {self.outer_var}")
except Exception: print("tERROR!!! Cannot access self.outer_var")
try: print(f"tself.inner_var = {self.inner_var}")
except Exception: print("tERROR!!! Cannot access self.inner_var")
print(f"tvar3 {var3}")
print("nnUSING THE CLASS DIRECTLYnn")
Sample.this_is_static_method(111)
Sample.this_is_class_method(222)
try: Sample.this_is_instance_method(333)
except Exception: print("==========nERROR!!! Cannot access Sample.this_is_instance_method")
print("nnUSING AN INSTANCE OBJECTnn")
sample_instance = Sample(444)
sample_instance.this_is_static_method(555)
sample_instance.this_is_class_method(666)
sample_instance.this_is_instance_method(777)
Выход:
USING THE CLASS DIRECTLY
==========
this_is_static_method
Sample.outer_var = my outer var
ERROR!!! Cannot access Sample.inner_var
var3 111
==========
this_is_class_method type(cls) <class 'type'> cls <class '__main__.Sample'>
cls.outer_var = my outer var
ERROR!!! Cannot access cls.inner_var
var3 222
__init__ var = 222
==========
ERROR!!! Cannot access Sample.this_is_instance_method
USING AN INSTANCE OBJECT
__init__ var = 444
==========
this_is_static_method
Sample.outer_var = my outer var
ERROR!!! Cannot access Sample.inner_var
var3 555
==========
this_is_class_method type(cls) <class 'type'> cls <class '__main__.Sample'>
cls.outer_var = my outer var
ERROR!!! Cannot access cls.inner_var
var3 666
__init__ var = 666
==========
this_is_instance_method type(self) <class '__main__.Sample'> self <__main__.Sample object at 0x1551aff90730>
self.outer_var = my outer var
self.inner_var = 444
var3 777