Earlier quoted context omitted.
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.
Understanding Python through its builtins
161–170 of 180 posts
Re: Understanding Python through its builtins
#162>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.
I'm not sure about that - it's still `type annotations` which jumps to https://sadh.life/post/builtins/mypy-guide and then jumps to your homepage.
Re: Understanding Python through its builtins
#163Earlier quoted context omitted.
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.
If you read the docs then you basically would not know about them. My experience mirrors the people upthread. I also found that the Python community is very hostile to the idea that the docs might be insufficient, in that people suggesting this in threads were frequently belittled or it was often suggested that the questant should just learn it like they did, or that it wasn't really all that hard.
Compare their ThreadPoolExecutors (Python's being inspired by Java's)
https://docs.python.org/3/library/concurrent.futures.html#co...
https://docs.oracle.com/javase/7/docs/api/java/util/concurre...
Re: Understanding Python through its builtins
#164Re: Understanding Python through its builtins
#165Earlier quoted context omitted.
> 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
#166Earlier quoted context omitted.
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…
“But!” I can hear people say, “I heard you could attach methods to instances in Ruby! How is this possible if Ruby never considers the instance in resolving a method call?”
Well, that’s tricky. The thing is, Ruby instances have no public members, instance variables are private (for direct access, but not in any strict way, because there are public methods called instance_variable_get and instance_variable_get on Object which…do exactly what the names say.)
But every Ruby instance conceptually has (though it doesn’t concretely have one unless you add something to it) a unique class for the instance that is the first thing in its class heirarchy. And you can add methods to that class (the instance “metaclass”, which is different than a Python metaclass) for the effect of attaching them uniquely to the instance itself.
Re: Understanding Python through its builtins
#167Earlier quoted context omitted.
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.
So the problem is some vendors ship libs that have failing asserts so cannot run in debug mode?
Re: Understanding Python through its builtins
#168Earlier quoted context omitted.
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
#169Earlier quoted context omitted.
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.
Yet Ruby and JS manage to do it somehow. To me it seems natural that join should be a method on the iterable, and I always have to pause to remember Python is different.
Ruby does it by having a mixin (Enumerable) that anything meeting a basic contract (roughly equivalent to the Python iterable protocol) can include to get an enormous block of functionality; Python doesn’t have (or at least idiomatically use as freely; ISTR that there is a way to do it) mixins like Ruby does.
Re: Understanding Python through its builtins
#170Earlier quoted context omitted.
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.
The ! convention is ok but I don't think it's optimal because, in the presence of higher-order functions and related concepts, it's often not clear if a function should be marked as !. For example if I have a map function that applies a function f to a sequence, should I call it map! because I might pass in a function f that mutates the input? If so then it seems like any function that takes a function as input, or a…
A very common case of this is mutating versions of non-mutating methods, but (1) mutating methods (in stdlib or other idiomatic code bases) that have no non-mutating equivalent are not named with a “!”, and (2) methods are sometimes named with “!” because they do dangerous things compared to a base method that are not mutating the receiver.