It's because the next function calls the next method of the object that passed in. 
next(...)
    x.next() -> the next value, or raise StopIteration
listiterators and generators both have the next method.
>>> iter(range(1)).__class__.next
<slot wrapper 'next' of 'listiterator' objects>
>>> iter(x for x in range(1)).__class__.next
<slot wrapper 'next' of 'generator' objects>
But a list doesn't have it. And that is the reason why it raises that exception.
>>> list.next
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'list' has no attribute 'next'
next doesn't care much about whether the object it's passed is an iterator or not.
>>> class Foo():
...     def next(self):
...             return "foo"
... 
>>> foo = Foo()
>>> next(foo)
'foo'
>>> next(foo)
'foo'
But adding the next method doesn't necessarily make it a collection/sequence/iterable.
>>> class Foo():
...     def next(self):
...             return "Foo"
>>> [x for x in Foo()]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iteration over non-sequence
>>> iter(Foo())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iteration over non-sequence
But adding the __iter__ method to it makes it one.
>>> class Foo():
...     def next(self):
...             return "Foo"
...     def __iter__(self): return self
... 
>>> [x for x in Foo()]
^CTraceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyboardInterrupt
>>> iter(Foo())
<__main__.Foo instance at 0x7fd77307c488>
The next seems to have some builtin intelligence when it comes to list. 
>>> class Foo():
...     pass
... 
>>> foo = Foo()
>>> next(foo)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: instance has no next() method
>>> next(range(20))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list object is not an iterator