Hamza Abbad Hamza Abbad - 14 days ago 3
Python Question

Instance method is not working from an object while it works perefctly from its class

This is the most strange error that I got since I started to program with Python years ago.

First, theses are my classes (Sorry for the long code):

class Quran(Iterable):

def __init__(self):
self.sourats = []

def __iadd__(self, other):
# There is some code here
pass

def __getitem__(self, sourat_num):
if not (isinstance(sourat_num, int) or isinstance(sourat_num, slice)):
raise TypeError('Indexing Quran can be done only using ints or slices')
if isinstance(sourat_num, int):
sourat_num -= 1
else:
sourat_num = slice(sourat_num.start - 1, sourat_num.stop)
try:
return self.sourats[sourat_num]
except IndexError:
return None

def __len__(self):
return len(self.sourats)

# Other methods ...

class Sourat(Iterable):

sourats_titles = [ # 114 strs here
]

def __init__(self, number, quran):
if not isinstance(number, int):
raise TypeError('number must be int')
if not isinstance(quran, Quran):
raise TypeError('quran must be Quran')
self.num = number
self.ayats = []
self.quran = quran

def __int__(self):
return self.num

def __iadd__(self, other):
# Some code here
pass

def __getitem__(self, ayat_num):
if not (isinstance(ayat_num, int) or isinstance(ayat_num, slice)):
raise TypeError('Indexing Sourat can be done only using ints or slices')
if isinstance(ayat_num, int):
ayat_num -= 1
else:
ayat_num = slice(ayat_num.start-1, ayat_num.stop)
try:
return self.ayats[ayat_num]
except IndexError:
return None

def __len__(self):
return len(self.ayats)

def location(self):
return self.num

def previous(self):
p_num = self.num-1
if p_num < 1:
return None
return self.quran[p_num]

def next(self):
n_num = self.num+1
if n_num > len(self.quran):
return None
return self.quran[n_num]

# Other methods ...

class Word(Iterable):

def __init__(self, number, text, features, ayat):
if not isinstance(number, int):
raise TypeError('number must be int')
if not isinstance(text, str):
raise TypeError('text must be str')
if not (isinstance(features, dict) and features['type'] in ('PREFIX', 'STEM', 'SUFFIX')):
raise TypeError('features[type] must be one of PREFIX, STEM, SUFFIX')
if not isinstance(ayat, Ayat):
raise TypeError('ayat must be Ayat')
self.num = number
self.text = text
self.root = features.get('ROOT', None)
self.lem = features.get('LEM', None)
self.type = features['type']
self.next = None
self.previous = None
self.ayat = ayat

def __iadd__(self, other):
# Some code here

def __hash__(self):
# Some code here
pass

def previous(self):
p_num = self.num-1
if p_num < 1:
previous_ayat = self.ayat.previous()
if previous_ayat:
return previous_ayat[-1]
else:
return None
return self.ayat[p_num]

def next(self):
n_num = self.num+1
if n_num > len(self.ayat):
next_ayat = self.ayat.next()
if next_ayat:
return next_ayat[0]
else:
return None
return self.ayat[n_num]

# Other methods ...


And this is what I am have in the main code :

quran_last_14_sourats = parse_quranic_corpus('quranic-corpus-morphology-0.4-last-14-sourats.txt')
sourat = quran_last_14_sourats[2]
ayat = sourat[2]
word = ayat[1]
assert isinstance(ayat, Ayat)
assert isinstance(word, Word)
print(ayat.previous())
print(ayat)
print(ayat.next())
print(Word.next(word)) # This works !!!
print(word.next()) # This doesn't work !!!


My problem is in the
next(self)
and
previous(self)
in the class
Word
, everything else works perfectly.

When I try to use
word.next()
or
word.previous()
, it complains that
NoneType is not callable
. I tried to
print(word.next)
and it showed
None
, but this is not logical because these two methods are inside the class
Word
. This problem doesn't happen in classes
Sourat
and
Ayat
even that they have the same structure. And the most crazy thing is that
Word.next(word)
works without any problem !

Is this a bug in Python 3 ? (BTW I am using the latest version: 3.5.2)

Answer

Is this a bug in Python 3 ?

In a word, no.

Instance members and instance methods share the same namespace. Thus, your line in Word.__init__():

self.next = None

obliterates the reference to the method Word.next() inside the newly-allocated Word object.

Comments