Live data from Hacker News

Understanding Python through its builtins

sadh.life

151–160 of 180 posts

Re: Understanding Python through its builtins

#151
post #108
post #98

This is a neat article, but it does have some errors. One subtle point that the post gets wrong: > So where does that come from? The answer is that Python stores everything inside dictionaries associated with each local scope. Which means that every piece of code has its own defined “local scope” which is accessed using locals() inside that code, that contains the values corresponding to each variable name. The dicti…

> Attribute lookup in Python is [...] an enormous tar pit Spot on. Python is widely described as a simple language, but the complexity of attribute lookup is one thing that shows that's not true at all. Many things in Python are easy , such as adding `@property` above a method definition to turn it into a getter. But `@property` is far from simple - the way it actually works is very complex (for example, properties h…

  > Python is widely described as a simple language, but the complexity
  > of attribute lookup is one thing that shows that's not true at all.
Python is a simple language to _learn_. My children learned the basics of Python before their seventh birthdays. But Python is not a simple language to _implement_.

Re: Understanding Python through its builtins

#152

>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.

It took me quite a long time to understand what happened there too!

(Pseudo code, let's call them num1 and num2 for better readability)

    num1 + num2 
    = num1.__add__(num2) 
    = num2 + 42 (that's why the order is important)
    = num2.__add__(42) 
    = 42 + 42 
    = 84

Re: Understanding Python through its builtins

#153
post #108

Earlier quoted context omitted.

> Attribute lookup in Python is [...] an enormous tar pit Spot on. Python is widely described as a simple language, but the complexity of attribute lookup is one thing that shows that's not true at all. Many things in Python are easy , such as adding `@property` above a method definition to turn it into a getter. But `@property` is far from simple - the way it actually works is very complex (for example, properties h…

> Python is widely described as a simple language, but the complexity > of attribute lookup is one thing that shows that's not true at all. Python is a simple language to _learn_. My children learned the basics of Python before their seventh birthdays. But Python is not a simple language to _implement_.

It’s an easy language to learn the basics of, sure. But the complexity of things like attribute lookup doesn’t only affect language implementors.

The complexity is all exposed to Python programmers, which makes the language hard to master and, unlike truly simple languages, too large for anyone to understand completely.

Re: Understanding Python through its builtins

#155
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.

What about list, dict, set, tuple, range and map then?

Re: Understanding Python through its builtins

#156

Earlier quoted context omitted.

"-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?"

Not because the -o mode also remove any block testing on "__debug__", and that's a very useful thing as well.

The original feature is perfect. But there is 5 good years of educating users so it can be used.

Re: Understanding Python through its builtins

#157
post #131
post #119

Earlier quoted context omitted.

Good article, thanks. It's worth pointing out that the summary (class hierarchy data descriptor > instance `__dict__` > class hierarchy other) only applies when looking up a normal attribute on a normal object: * Special-method lookup (e.g. of `__add__` when you do `a + b`) works differently because it doesn't look at the instance `__dict__`, only the class hierarchy. * Lookup on a class works differently because as…

You might even say that without classes python would be a simpler language, while keeping almost all its power :)

It's a fun dream, but without the ability for a variable to carry along with it a notion of, say, how it implements slice notation, or the ability to avoid verbose names like foo_to_repr(foo) and bar_to_repr(bar) so that names don't collide... arguably we never would have seen the rise of scientific Python! Object oriented programming is an incredibly good abstraction for a lot of real-world scenarios.

Re: Understanding Python through its builtins

#158
post #84
post #44

Earlier quoted context omitted.

random.shuffle() has bitten me that way a few times too: array = random.shuffle(array) because I expected it to return a copy or reference, instead making my array None. It would also enable chaining operations: array = array.append(A).append(B).sort() In-place vs immutable copy is a language design choice with tradeoffs on both sides, but there's no reason that I can see to not return a reference to the list. Perhap…

In Python, a function that makes and returns a copy would be idiomatically named shuffled(). Consider sorting: xs.sort() # in-place ys = sorted(xs) # copy As for functions returning the object - I think it's a hack around the absence of direct support for such repetition in the language itself. E.g. in Object Pascal, you'd write: with array do begin append(A); append(B); sort; end; Or better yet, in Smalltalk: array…

Also

https://dart.dev/guides/language/language-tour#cascade-notat...

Re: Understanding Python through its builtins

#159
post #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. Simil…

Yup, I'll fix this, thanks for pointing it out.

Re: Understanding Python through its builtins

#160
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.

Nope, += also creates a binding! Try this:

   xs = [1, 2]

   def foo():
      xs += [3]

   foo()
You'll get an exception saying that local variable xs was used before it was assigned - precisely because += created a new local binding for xs inside foo.
Post reply on HN