An "adapter", superset of an iterator

Thomas Passin list1 at tompassin.net
Wed May 3 13:30:50 EDT 2023


On 5/3/2023 5:45 AM, fedor tryfanau wrote:
> I've been using python as a tool to solve competitive programming problems
> for a while now and I've noticed a feature, python would benefit from
> having.
> Consider "reversed(enumerate(a))". This is a perfectly readable code,
> except it's wrong in the current version of python. That's because
> enumerate returns an iterator, but reversed can take only a sequence type.

Depending on what you want to give and receive, enumerate(reversed(a)) 
will do the job here.  Otherwise list() or tuple() can achieve some of 
the same things.

> The feature I am describing (and proposing) solves this.
> Introducing an adapter type: this is an iterator, but it's items can be
> accessed out of order.
> More formally it has to:
> 1. Have __getitem__ to allow access by index
> 2. Have __len__
> 3. Be immutable
> (It is a lot like the sequence protocol)
> 
> An adapter can be converted to an iterator by accessing it from 0 to
> len(adapter). Which is done by iter(). (or by __iter__, I don't know which
> implementation would be "right")
> ```
> iter(a)
> #is equivalent to
> (a[i] for i in range(len(a)))
> ```
> For example any tuple is a valid adapter and any list can be easily
> converted to one.
> 
> Built-in adapter-generators:
> "map" function should really return an adapter.
> ```
> #possible implementation
> m=map(lambda x:x+1,[1,2,3,4,5])
> #lambda is not called
> print(m[3])# gives 5 by calling the lambda on list's 3rd element, which is 4
> #simplified implementation
> class map:
>      def __init__(self,f,a):
>          self.f=f
>          self.a=a
>      def __getitem__(self,idx):
>          return self.f(self.a[idx])
>      def __len__(self):
>          return len(self.a)
> ```
> enumerate should really return an adapter
> ```
> #simplified implementation
> class enumerate:
>      def __init__(self,a):
>          self.a = a
>      def __getitem__(self,idx):
>          return idx,self.a[idx]
>      def __len__(self):
>          return len(self.a)
> ```
> reversed should really return an adapter
> ```
> #simplified implementation
> class reversed:
>      def __init__(self,a):
>          self.a = a
>          self.length=len(a)
>      def __getitem__(self,idx):
>          return self.a[self.length-idx-1]
>      def __len__(self):
>          return self.length
> ```
> zip should really return an adapter
> range should really return an adapter
> filter should *not* return an adapter
> 
> All of those functions return an adapter and take in an adapter. But some
> (excluding "reversed") should be able take an iterator and return an
> iterator.
> So the way I imagine a possible release version to work is that
> "reversed(enumerate(a))" works if a is an adapter and throws an exception
> if not
> 
> Perhaps there should be even an adapter comprehension:
> ```
> Add1 = (a+1 for a)
> #is equivalent to
> Add1 = lambda s: map((lambda a: a+1),s)
> transformed = Add1([1,2,3])
> print(transformed[1])# should be 3
> ```
> 
> This adapter feature also allows you to not use a key argument "key=" for
> certain functions (which could be non-existing). For example bisect.bisect
> functions before 3.10 didn't have a key= argument. Some third-party
> libraries could do this with it's functions too.
> 
> (Subject to change)



More information about the Python-list mailing list