123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- .. Copyright (C) 2001-2019 NLTK Project
- .. For license information, see LICENSE.TXT
- ==========================================
- Unit tests for the nltk.utilities module
- ==========================================
- overridden()
- ~~~~~~~~~~~~
- >>> from nltk.internals import overridden
- The typical use case is in defining methods for an interface or
- abstract base class, in such a way that subclasses don't have to
- implement all of the methods:
- >>> class EaterI(object):
- ... '''Subclass must define eat() or batch_eat().'''
- ... def eat(self, food):
- ... if overridden(self.batch_eat):
- ... return self.batch_eat([food])[0]
- ... else:
- ... raise NotImplementedError()
- ... def batch_eat(self, foods):
- ... return [self.eat(food) for food in foods]
- As long as a subclass implements one method, it will be used to
- perform the other method:
- >>> class GoodEater1(EaterI):
- ... def eat(self, food):
- ... return 'yum'
- >>> GoodEater1().eat('steak')
- 'yum'
- >>> GoodEater1().batch_eat(['steak', 'peas'])
- ['yum', 'yum']
- >>> class GoodEater2(EaterI):
- ... def batch_eat(self, foods):
- ... return ['yum' for food in foods]
- >>> GoodEater2().eat('steak')
- 'yum'
- >>> GoodEater2().batch_eat(['steak', 'peas'])
- ['yum', 'yum']
- But if a subclass doesn't implement either one, then they'll get an
- error when they try to call them. (nb this is better than infinite
- recursion):
- >>> class BadEater1(EaterI):
- ... pass
- >>> BadEater1().eat('steak')
- Traceback (most recent call last):
- . . .
- NotImplementedError
- >>> BadEater1().batch_eat(['steak', 'peas'])
- Traceback (most recent call last):
- . . .
- NotImplementedError
- Trying to use the abstract base class itself will also result in an
- error:
- >>> class EaterI(EaterI):
- ... pass
- >>> EaterI().eat('steak')
- Traceback (most recent call last):
- . . .
- NotImplementedError
- >>> EaterI().batch_eat(['steak', 'peas'])
- Traceback (most recent call last):
- . . .
- NotImplementedError
- It's ok to use intermediate abstract classes:
- >>> class AbstractEater(EaterI):
- ... pass
- >>> class GoodEater3(AbstractEater):
- ... def eat(self, food):
- ... return 'yum'
- ...
- >>> GoodEater3().eat('steak')
- 'yum'
- >>> GoodEater3().batch_eat(['steak', 'peas'])
- ['yum', 'yum']
- >>> class GoodEater4(AbstractEater):
- ... def batch_eat(self, foods):
- ... return ['yum' for food in foods]
- >>> GoodEater4().eat('steak')
- 'yum'
- >>> GoodEater4().batch_eat(['steak', 'peas'])
- ['yum', 'yum']
- >>> class BadEater2(AbstractEater):
- ... pass
- >>> BadEater2().eat('steak')
- Traceback (most recent call last):
- . . .
- NotImplementedError
- >>> BadEater2().batch_eat(['steak', 'peas'])
- Traceback (most recent call last):
- . . .
- NotImplementedError
- Here's some extra tests:
- >>> class A(object):
- ... def f(x): pass
- >>> class B(A):
- ... def f(x): pass
- >>> class C(A): pass
- >>> class D(B): pass
- >>> overridden(A().f)
- False
- >>> overridden(B().f)
- True
- >>> overridden(C().f)
- False
- >>> overridden(D().f)
- True
- It works for classic classes, too:
- >>> class A:
- ... def f(x): pass
- >>> class B(A):
- ... def f(x): pass
- >>> class C(A): pass
- >>> class D(B): pass
- >>> overridden(A().f)
- False
- >>> overridden(B().f)
- True
- >>> overridden(C().f)
- False
- >>> overridden(D().f)
- True
|