Live data from Hacker News

Understanding Python through its builtins

sadh.life

141–150 of 180 posts

Re: Understanding Python through its builtins

#141

Earlier quoted context omitted.

Unless I'm misunderstanding, they are wrapping their asserts in try/catch blocks? That's... yikes.

Most likely they just `assert` error conditions and let that blow up as error reporting, rather than write a full conditional and raise a custom exception. I’ve been guilty of that in my own code when I just want to tell myself about an error.

Isnt just assert the error condition how assert is actually intended to be used?

Re: Understanding Python through its builtins

#142

Earlier quoted context omitted.

Seems like a better idea would be to make a separate flag "--remove-assertions" for people who desire that.

"-o" is mostly "--remove-assertions" already, so that wouldn't help. While today's use case for assert is unit testing, the actual killer feature of the keyword is that it's removed only from prod. The idea is that you can write things like function contracts, that are expensive, but only exist in dev. Now, if one of you dependencies use assert for something they expect to still be in prod, which is the problem we ar…

Before this thread i had no idea assert was debug only in python.

Another solution would be to accept the current role of assert as quick error checking and add in debug_assert to indicate a conditional error check. The biggest issue with that approach is that a majority will suddenly ask "Wait, python has a debug mode?"

Re: Understanding Python through its builtins

#143
post #78

Earlier quoted context omitted.

Thank you! Things like `list.append` modifying in-place might feel like a flaw to some, but I think Python is really consistent when it comes to its behaviour. If you ask a person who comes from an object-oriented world, they'll say it only makes sense for a method on an object to modify that object's data directly. There's always ways to do things the other way, for example you can use x = [*x, item] to append and c…

One related area where Python is not consistent is operators like +=. In pretty much all other languages that have them, the expected behavior of A+=B is exactly the same as A=A+B, except that A is only evaluated once. Now lets look at lists in Python: xs = [1, 2] ys = xs ys = ys + [3] print(xs, ys) This prints [1, 2] [1, 2, 3], because the third line created a new list, and made ys reference that. On the other hand,…

The rule in Python is that `=` creates a name binding, where as `+=` does not. That's pretty consistent as far as I can tell.

Re: Understanding Python through its builtins

#144
post #78

Earlier quoted context omitted.

One related area where Python is not consistent is operators like +=. In pretty much all other languages that have them, the expected behavior of A+=B is exactly the same as A=A+B, except that A is only evaluated once. Now lets look at lists in Python: xs = [1, 2] ys = xs ys = ys + [3] print(xs, ys) This prints [1, 2] [1, 2, 3], because the third line created a new list, and made ys reference that. On the other hand,…

The rule in Python is that `=` creates a name binding, where as `+=` does not. That's pretty consistent as far as I can tell.

The inconsistency is that for immutable objects (or more generally, objects that have __add__ but not __iadd__), '+=' does create a name binding.

After 'a = 300; b = 50000',

    a += b
is exactly the same as

    a = a + b
In this case, a new object is created with the value of a + b which then gets bound to the name a.

Re: Understanding Python through its builtins

#145
The list comparison here is also true when the first list is a prefix of the other:

    class list:
        def __eq__(self, other):
            return all(x == y for x, y in zip(self, other))

            # Can also be written as:
            return all(self[i] == other[i] for i in range(len(self)))
run that with `[1,2,3]` and `[1,2,3,4]` and it'll be true because it only checks up to the 3.

It's probably simplest to compare `len(self) == len(other)` before.

Similarly, the set comparison will also be true if the first is a subset of the other.

Re: Understanding Python through its builtins

#146
post #138

Thank you for writing the post. Newbie question about “nonlocal” from your example: def outer_function(): x = 11 def inner_function(): nonlocal x x = 22 print('Inner x:', x) inner_funcion() print('Outer x:', x) I get how the example works, but don’t see the point of the declaration? If I just left out the “nonlocal x” line, wouldn’t the example still work the same?

Python assumes that all assignments assign to the current scope. So by default when you reach "x = 22", it would create a new variable called "x" in the inner_function() scope which overrides the variable "x" in the outer_function() scope. So when you print "Inner x" you would only be printing the inner_function() version of x, not the outer_function() version, which would remain at 11.

This is a consequence of python not having explicit variable definition. Here it'll decide to define a new x instead of seeing the old one.

And that's also usually what you want because otherwise a function would start altering variables in the enclosing scope if they happen to exist!

E.g.

    foo = 42

    def myfunc(bar):
        foo = bar + 1
        print(foo)
    myfunc(6)
    print(foo) # would print "7" if the "foo =" above took the nonlocal foo automatically!
So the trade-off is to require "nonlocal" if you ever need a variable from the enclosing scope.

Re: Understanding Python through its builtins

#147
post #121

Earlier quoted context omitted.

False = None = True Is probably the most ridiculous thing for a language to support. And yet...

... and yet, it is a SyntaxError. False = True = None works in Python 2, and it is just because the separate Boolean type was a late addition.

Oops, yep. I've seen somebody overwrite False in the wild, but I thought None was writable too. Glad for that smidgen of sanity...

Re: Understanding Python through its builtins

#148

Earlier quoted context omitted.

Most likely they just `assert` error conditions and let that blow up as error reporting, rather than write a full conditional and raise a custom exception. I’ve been guilty of that in my own code when I just want to tell myself about an error.

Isnt just assert the error condition how assert is actually intended to be used?

Depends. The issue is that since `assert` is stripped out in “O” mode, if the codebase depends on `assert` for correctness… they’re not compatible.

Re: Understanding Python through its builtins

#149
post #136

> Python has exactly 6 primitive data types (well, actually just 5, but we’ll get to that). 4 of these are numerical in nature, and the other 2 are text-based. Let’s talk about the text-based first, because that’s going to be much simpler. What is your definition of a primitive data types? All of these have object as a superclass, so I wouldn't call them primitive data types in python. Maybe there is just 1 primitive…

In my case I meant it as things that only extend from object. Kinda like how prime numbers only have two factors including themselves.

Re: Understanding Python through its builtins

#150

>As a bonus, this also adds support for adding two MyNumber classes together: Merely having `__add__` (without `__radd__`) is enough to add two MyNumber classes together in your case. >It mostly exists to support type annotations, The link for "type annotations" is broken.

Type annotations link is fixed, thank you!

Just `__add__` doesn't work for me. I get:

    TypeError: unsupported operand type(s) for +: 'int' and 'Number'
Here's the code:

    class Number:
        def __add__(self, x):
            return 42 + x

    num = Number()
    print(num + num)
Edit: Okay. replacing `42 + x` with `x + 42` actually makes it work. But I'll be honest I have no idea what happened there.
Post reply on HN