If you have suggestions for improvements for the article, let me know here! Thanks again.
What learning APL taught me about Python
81–90 of 104 posts
Re: What learning APL taught me about Python
#82Earlier quoted context omitted.
Ah yes, I've been doing this with stdout.write since Python 2; it didn't occur to me that when Python 3 turned print into a function that would make it usable in lambdas! You're right that the walrus makes assignment more usable; we can also call methods like .__setitem__ to get similar effects. Unfortunately the walrus seems to suffer the same broken/ambiguous scoping as assignment statements, e.g. >>> a = 1 >>> b =…
b = lambda: (a := 2, print(a)) Hmm, need to put the assignment before. Can't access nonlocals unless you only read the the var and don't write to it. That's the way functions in python work as well.
No, that would not have the intended behaviour: your `print(a)` is reading a fresh local variable, defined by the `:=` expression (which shadows that from the outer scope), so it will output '2'. The intended behaviour is to print '1' and reassign the outer name; but we can't do that (that's why I chose it as an example!)
> Can't access nonlocals unless you only read the the var and don't write to it. That's the way functions in python work as well.
Yes, that is precisely what I meant when I said it "suffers the same broken/ambiguous scoping as assignment statements".
Python took a haphazard, WorseIsBetter approach to assignment/declaration/scoping. The resulting behaviour is complex, confusing and involves spooky action-at-a-distance (e.g. the meaning of my `print(a)` expression was altered by the presence of an ':=' expression which hadn't been reached yet!). Since this doesn't really affect simple "top to bottom" scripts, it only became an issue once large applications and frameworks started emerging; by that time it was too late to fix, since there was too much Python code in the wild to justify such a large breaking change :(
Re: What learning APL taught me about Python
#83Someone else has mentioned it, but I would have gone with: sum(1 for age in ages if age > 17) with the other method you're treating a boolean as an int. Weak typing.
bool is explicitly documented to be a subclass of int [1][2], so while it might be an obscure feature, or subjectively not someone's preferred style, I don't see any typing related issue. In general I don't think that treating an object as if it were an instance of one of its base classes is weak typing. [1]: https://docs.python.org/3/library/functions.html?highlight=s... [2]: https://docs.python.org/3/library/stdtyp…
if 23:
print('hello')
and it'll print 'hello'. But I'd prefer a strongly typed approach where this code would give an error saying, 'a bool is expected here'. Sure it's a subjective thing, and this is just my preference.Re: What learning APL taught me about Python
#84How APL made me a better Python developer by Rodrigo Girão Serrão: https://www.youtube.com/watch?v=tDy-to9fgaw
Re: What learning APL taught me about Python
#85Someone else has mentioned it, but I would have gone with: sum(1 for age in ages if age > 17) with the other method you're treating a boolean as an int. Weak typing.
Its not weak typeing, bools are ints. “I don’t know the type hierarchy used in language X” is not the same thing as “language X is weakly typed”. Python 3.11.4 (tags/v3.11.4:d2340ef, Jun 7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> isinstance(True, int) True >>> isinstance(False, int) True >>> issubclass(bool, int) True
Re: What learning APL taught me about Python
#86Earlier quoted context omitted.
I agree with the improvement in readability but still like the bool/int equivalence: sum(int(age > 17) for age in ages) Every nanosecond is vital!
Interesting, so I did a little test: python -m timeit 'sum(1 for age in range(100000) if age > 17)' 50 loops, best of 5: 5.08 msec per loop python -m timeit 'sum(int(age > 17) for age in range(100000))' 50 loops, best of 5: 7.96 msec per loop python -m timeit 'sum(age > 17 for age in range(100000))' 50 loops, best of 5: 4.78 msec per loop
Plus here on each iteration `int` has to be loaded from the globals before it can be called.
Re: What learning APL taught me about Python
#87Earlier quoted context omitted.
I feel like the numpy version is most concise, most readable, and most array-ish: np.sum(age>17) (Assumes age is a np.array)
Yes, this is VERY close to the APL way: +/ages>17 OP here; maybe I'll add a comment to the article to make the comparison between NumPy and APL for this expression. Thanks!
Re: What learning APL taught me about Python
#88I feel like this kind of operation on a list feels more naturally expressed by filtering the list and taking the length of the filtered list. Like this line of JS feels so much easier to read than that line of python: ages.filter(age => age > 17).length Directly translating this approach to python: len(list(filter(lambda age: (age > 17), ages))) Although a better way to write this in python I guess would be using lis…
length $ filter (> 17) ages
And you can also count pred = length . filter pred
count (> 17) agesRe: What learning APL taught me about Python
#89I feel like this kind of operation on a list feels more naturally expressed by filtering the list and taking the length of the filtered list. Like this line of JS feels so much easier to read than that line of python: ages.filter(age => age > 17).length Directly translating this approach to python: len(list(filter(lambda age: (age > 17), ages))) Although a better way to write this in python I guess would be using lis…
select count(*) from ages where age > 17
Re: What learning APL taught me about Python
#90I feel like this kind of operation on a list feels more naturally expressed by filtering the list and taking the length of the filtered list. Like this line of JS feels so much easier to read than that line of python: ages.filter(age => age > 17).length Directly translating this approach to python: len(list(filter(lambda age: (age > 17), ages))) Although a better way to write this in python I guess would be using lis…
E: And I guess the lambda and explicit list-cast too. cf.
(count (filter #(> % 17) ages))