all() function not working as it should.

According to Cpython official documentation the all() function defination is

all(iterable) →
Return True if all elements of the iterable are true (or if the iterable is empty). Equivalent to:

"""all() function analogy in python"""
def all(iterable):
    for element in iterable:
        if not element:
            return False
    return True
def is_string(value: str) -> bool:
    print("function called")
    return isinstance(value, str)


x = 123
result: bool = all([is_string(x), x.isidigit()])



Output --> 

function called
Traceback (most recent call last):
  File "/workspaces/workspace/main.py", line 7, in <module>
    result: bool = all(is_string(x), x.isidigit())
                                     ^^^^^^^^^^
AttributeError: 'int' object has no attribute 'isidigit'

Hint 1: If you are a beginner, and you believe that a major feature in a programming language is broken, and that millions of people over decades have not found it, you should consider strongly that the error might actually be yours.

Hint 2: If you get an error message, try reading it before using up a lot of other people’s time on it. In this case, the error message is completely clear.

Hint 3: The error message you report shows a different piece of code than the code you posted.

Hint 4: Try this

x = 123
x.isdigit()

3 Likes

This would work correctly if the elements of the list were evaluated lazily, but alas they are not, because by the time it’s passed into all the list already needs to exist.

You could achieve what you want with a generator:

def is_numeric_string_iterator(value: object) -> Iterator[bool]:
    yield is_string(x)
    yield x.isdigit(x)

result = all(is_numeric_string_iterator(x))

Of course this would still break if you iterated over this generator with anything other than all and a type checker would complain that object does not implement isdigit.

If you want short circuiting just use the boolean operators, the following will always work:

result = is_string(x) and x.isdigit()

Although a type checker would still complain unless you changed is_string to:

def is_string(value: object) -> TypeGuard[str]:
    return isinstance(value, str)

This doesn’t break the code - it just means that you don’t get short-circuiting.

The issue in OP’s code is clearly nothing to do with short-circuiting - there’s just a typo in one of the method names, causing an error that directly explains the problem.

Fixing the typo would not resolve the main misunderstanding in that code. x is an integer so it doesn’t have an isdigit method either, so the code would still fail at the same place, because both elements of the list get evaluated before all is called.

Ah, true, it hadn’t occurred to me that the point was to use short-circuiting to avoid the TypeError.