Live data from Hacker News

Understanding Python through its builtins

sadh.life

111–120 of 180 posts

Re: Understanding Python through its builtins

#111

Earlier quoted context omitted.

The advantage of mutating operations always returning None is that you can easily tell whether a mutation is happening by looking at the code. If you see y = f(x) that means x is unchanged, whereas if you see just f(x) on a line that means something stateful is happening.

I really like ruby's method naming convention for this: * `sort(arr)` returns a sorted copy of the input * `sort!(arr)` returns the sorted original methods that return booleans end in `?`, like `arr.sorted?` It's just a convention, but it's a nice way to let the writer know what will happen.

> `sort(arr)` returns a sorted copy of the input

> `sort!(arr)` returns the sorted original

Python has a naming convention as well: `sorted(arr)` returns a sorted copy and `arr.sort()` works in-place (and returns None). However, I've always thought it's a bit odd that one is a function and the other is a method.

Re: Understanding Python through its builtins

#112
post #88

Earlier quoted context omitted.

Yes! When I learned Kotlin, I just read through the docs, and then knew of basically all the different concepts in the language. For Python, the docs were comparably very bad. For instance, Decorators aren't mentioned even once in the "The Python Tutorial". In "The Python Language Reference" (if one even bother to read such a dry document) it's barely mentioned in passing. How should a new user know it's a concept an…

As a non-Python dev I tried the other day to read up how decorators work in Python using the docs, can’t say it helped.

[deleted]

Re: Understanding Python through its builtins

#113
post #88

Earlier quoted context omitted.

Yes! When I learned Kotlin, I just read through the docs, and then knew of basically all the different concepts in the language. For Python, the docs were comparably very bad. For instance, Decorators aren't mentioned even once in the "The Python Tutorial". In "The Python Language Reference" (if one even bother to read such a dry document) it's barely mentioned in passing. How should a new user know it's a concept an…

As a non-Python dev I tried the other day to read up how decorators work in Python using the docs, can’t say it helped.

Decorators are very simple. I'm not surprised that there's not much documentation about them - there's just not much to say.

    @decorator
    def f(...): ...
is equivalent to:

    def f(...): ...
    f = decorator(f)
That's it.

Re: Understanding Python through its builtins

#114

Cute fact about __debug__: it is one of the only ways to get compile-time conditionals in Python. Performing a comparison with `if __debug__:` will output byte code for the ensuing statement if and only if the interpreter is in debug mode - notably, in `-O` mode, it will not even generate a load of __debug__ and a conditional jump, and acts as if the statement didn’t exist at all.

Unfortunatly you often can't use -o because of the 3rd party libs that didnt' get the memo and use assert for error checking. We still have -X dev and sys.flags but it's runtime only.

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

Re: Understanding Python through its builtins

#115

Cute fact about __debug__: it is one of the only ways to get compile-time conditionals in Python. Performing a comparison with `if __debug__:` will output byte code for the ensuing statement if and only if the interpreter is in debug mode - notably, in `-O` mode, it will not even generate a load of __debug__ and a conditional jump, and acts as if the statement didn’t exist at all.

that is indeed interesting. Mind if I add this in the article?

Sure, go ahead :)

Re: Understanding Python through its builtins

#116
post #16
post #12

Earlier quoted context omitted.

>Python is really consistent when it comes to its behaviour True, though you end up with things like: ' '.join(thelist) Instead of thelist.join(' ') Because of the somewhat aggressive mantra to be consistent.

But that's good. Because a string just needs to know aboit interable to perform that operation whereas every iterable would need to implement it's own join if you had it the other way around.

It may be necessary in python, but in general, a language could allow you to define a join method on the iterable superclasss/trait/interface that iterates over the elements, converting each to a string, and inserting the separator between each of them.

For example, scala has Iterable#mkstring (https://docs.scala-lang.org/overviews/collections-2.13/trait...)

Re: Understanding Python through its builtins

#118
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…

https://blog.peterlamut.com/2018/11/04/python-attribute-look... is a great overview of how this works. Start with the summary at the end!

The really cool thing about this, how descriptors have their __get__ called, is that methods are implemented this way. So when you access instance.method(), it’s a normal lookup for the attribute named “method”, which is (normally) itself a descriptor, so the __get__ magic is called and this binds the method to the instance at the moment it’s needed! Then you can just call it like a normal function. It’s incredibly elegant but extremely obscure. And vital to understand if you want to dive into monkey patching, which is an incredible skill to have!

Re: Understanding Python through its builtins

#119
post #118
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…

https://blog.peterlamut.com/2018/11/04/python-attribute-look... is a great overview of how this works. Start with the summary at the end! The really cool thing about this, how descriptors have their __get__ called, is that methods are implemented this way. So when you access instance.method(), it’s a normal lookup for the attribute named “method”, which is (normally) itself a descriptor, so the __get__ magic is calle…

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 well as looking at `__dict__`, it has to consider superclasses.

Much of the complexity relates to the different ways of handling the instance `__dict__`. By contrast, Ruby is able to have much simpler lookup rules because it never considers the instance, only ever the class hierarchy.

Re: Understanding Python through its builtins

#120
post #28

In addition to this, I highly recommend just reading the codebase. I haven't written C since college and it's remarkably readable. I once tried to catalogue all the stdlib operations which release the GIL, meaning if you use only those (well, only those "heavy" bits, you can still use other small blocking glue bits), you can do "real" multithreading. It was a fun exercise!

> I highly recommend just reading the codebase Me too. When I used to write Ruby I read a lot of CRuby source code. I achieved a much deeper understanding of the language that way. Even answered some really fun stackoverflow questions. Now the first thing I do when I see a new language is read its source code.

Yep, when I was writing PHP I found myself digging into php-src on a regular basis to see what exactly was going on. PHP's documentation is good but the code is much more explicit.
Post reply on HN