As someone who has had a lifetime of on-off relationships with attempting to become a competent programmer, (BASIC, assembler, C, Pascal, Visual Basic, C++ and others that I can no longer remember), Python is the only language that has helped me become anywhere near useful or proficient as a programmer. I've managed to build a couple of -genuinely useful- applications (one of which is being used daily in my girlfriend's school), which hasn't been the case for anything else.
I've found that Python is simple enough to learn, and hasn't really been any kind of a limitation for me - this may be because of me, not the language - OK, I appreciate that I'm not going to be writing 3D games or real-time audio apps in it, but for what I've been trying to do (solve real-world problems), it's been amazing. I even programmed a 'play sound effects when you press a MIDI controller' system which I used at a show with 20,000 people attending this summer, replacing a massively over-complex (and expensive) audio environment with about 30 lines of Python combined with two libraries I spent an afternoon learning.
That, for me, is why I like Python.
TIL 3D games and real-time audio apps are not "real-world problems".
def binds it to a name at the same time, which is remembered in the object (which AFAIK isn't really used for anything except maybe debugging tools), lambda returns an anonymous one. The resulting object can be passed around in both cases.
the point was in something like f#, lambda creates a function which can then be bound to a name if you want. if you do so, this is identical to the "normal" function definition because that is really just syntactic sugar for creating lambda functions and then binding it to a name.
Similarly, Python basically keeps track of "proper" names for proper functions, but can't/won't do so for lambdas.
Because lambdas don't have function names.
the def syntax merely sets the name property on the function object too, since it has a name to set available. As said in other comments, nice for interactive use, irrelevant otherwise.
>>> normalize_case = lambda s: s.casefold()
>>> normalize_case
<function <lambda> at 0x034B04B0>
>>> normalize_case.__qualname__ = "normalize_case"
>>> normalize_case
<function normalize_case at 0x034B04B0>
vs >>> def normalize_case(s):
return s.casefold()
>>> normalize_case
<function normalize_case at 0x00594420>
>>> normalize_case.__qualname__
'normalize_case'however, this still goes in the bucket of why i personally dislike python. this just seems sloppy and overly complicated.
for example, i tested this out myself.
> test = lambda x : x*x
> test
=> <function <lambda> at 0x7ff6221d76e0>
> test.__qualname__
Traceback (most recent call last):
File "python", line 1, in <module>
AttributeError: 'function' object has no attribute '__qualname__'
> test.__qualname__ = "test"
> test
=> <function <lambda> at 0x7ff6221d76e0>
so the repl still reports <lambda> instead of test. actually it turns out that even def doesn't seem to set the __qualname__ property, so i don't get the same thing as you (i am using repl.it which apparently uses python 2.7.10). however, using dir(test) showed that there is the func_name property. > def test2(x):
> return x*x
> test2.__qualname__
Traceback (most recent call last):
File "python", line 1, in <module>
AttributeError: 'function' object has no attribute '__qualname__'
> test2.func_name
=> 'test2'
> test.func_name
=> '<lambda>'
that seems to be the property that the repl reports, as it gets set by the lambda assignment and the def keyword to the function name. (i verified that by altering the func_name property manually.)yet, somehow, people call python "simple".
Perhaps it would help if you didn't think of "lambda" as defining a lambda function, but something more prosaic like "defexpr", and that Python doesn't have lambda functions at all?
As to your experiments, you have found one of the many differences between Python 2 and Python 3.
After researching F# for about 10 minutes, perhaps you might think of Python 2 as being like OCaml and Python 3 being like F# - they are two instances of the same language family, with a mutually compatible language subset, but many incompatibilities.
You've bitten onto a more or less internal detail (I've TA'ed a bunch of undergrad courses in Python, and it's firmly in the land of things students don't know if they don't discover it on their own) and use that and seemingly quite little grasp of how Python works to argue that it isn't simple, while of course languages you are more familiar with are better.
As far as I know, the __qualname__ property was introduced in Python3.3, so obviously you wouldn't see it in any Python 2 version.
python's version bifurcation problem is its problem, not mine. the problem exists.
Here are some reasons why I like it:
It's cleaner to read because there aren't curly braces and semicolons cluttering up the code.
It's cleaner to write because the expressions are simpler and look like something readable instead of line noise.
It has a REPL, so it's easy to experiment.
It doesn't force me to write boilerplate code, such as types for every variable declaration or everything having to be a class or huge amounts of scaffolding just to write "Hello, world!".
I'm sure I could think of more, but those are what come to mind on the spur of the moment.
I think the GP's point was that functional languages give you similar benefits, but with more uniform and disciplined behavior of many language features. Why FP is not more widely used compared to imperative language is another topic though.
I love JS because it's flexible and doesn't lock me into a paradigm. I can be as strict as I want to be. In the end, I think it depends on how someone thinks about problems. I tend to bend my thinking depending on the type of problem and how I might optimally solve said problem. When I need something else (often for performance), I'll circle around at that point for that part.
for example, in all three languages above, expressions are much easier to understand because they always return a value. this makes code easier to reason about. this is not true in python.
the languages i mentioned do have static typing but they have type inference. so you get the best of both worlds. you do need to type annotate at some points to clarify things, but this isn't a problem as it documents to both the user and compiler.
given your above reasons, you owe it to yourself to learn an ml. there is the programming languages course on coursera by dan grossman, which uses sml in the first part, and the ocaml mooc just started where you still have time to register and complete it.
https://www.coursera.org/learn/programming-languages
https://www.fun-mooc.fr/courses/course-v1:parisdiderot+56002...
F# has curly braces. Also, as you say, it requires some type annotations.
I see that F# has a REPL, but it seems bolted on as an afterthought instead of being an integral part of the language. (Also, it's not clear whether the REPL is available in Mono on Linux. I am allergic to Windows and anything built by Microsoft.)
> expressions are much easier to understand because they always return a value. this makes code easier to reason about. this is not true in python
Huh? Python expressions always return a value.
Perhaps what you mean is that Python also has statements, which do not return a value, whereas these languages do not--everything is an expression, as in Lisp?
> you owe it to yourself to learn an ml
I don't owe it to myself to learn anything unless I decide to. I wasn't trying to convince anyone else to use Python; I was just giving reasons why I like Python. Please extend me the same courtesy when you talk about things you like about your favorite languages.
> I see that F# has a REPL, but it seems bolted on as an afterthought instead of being an integral part of the language. (Also, it's not clear whether the REPL is available in Mono on Linux. I am allergic to Windows and anything built by Microsoft.)
well that first sentence is simply not true, and i don't know what gave you that impression. f#'s repl, f# interactive, is available on linux through mono and will soon be available through .net core. i can't help you being needlessly allergic to a major operating system or company. f# came out of microsoft research.
> Huh? Python expressions always return a value.
they do? take:
def test(x):
"something"
so what does test(2)
return?> I don't owe it to myself to learn anything unless I decide to. I wasn't trying to convince anyone else to use Python; I was just giving reasons why I like Python. Please extend me the same courtesy when you talk about things you like about your favorite languages.
i don't know why you're upset. i am not for sure where i was discourteous. i didn't mean anything by my statement other than to check out the languages and courses (the coursera one is very good). if those are your reasons for python, i just thought you would honestly like an ML-based language. i just used "owe it to yourself" as an expression, which apparently came out wrong through text. of course you don't owe anyone anything. i was just making a suggestion.
Yes, and thanks for acknowledging that. But then the phrase "owe it to yourself" didn't really communicate your intent correctly, which is why I objected to it.
> i guess that is true in python3 but it is not in python 2.7.
No, it's always been there.
>>> def f():
... pass
...
>>> f() is None
TrueTrue
>>> None
>>> print(None)
None
In the future, you might want to refrain from strong criticism of a thing you're not familiar with. That habit leads to all sorts of -isms. test(2) is None
and got false. i just now went to try it out again at home and got true. i don't know what to tell you other than something must have got shadowed somewhere. peter@localhost:~$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def test(x):
... "something"
...
>>> test(2) is None
True
And Python 2: peter@localhost:~$ python
Python 2.7.12 (default, Dec 4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def test(x):
... "something"
...
>>> test(2) is None
True
If you post such a transcript from your REPL session where you get False, it should be easier to tell what's different between your setup and mine (which is a stock Python install on Ubuntu 16.04).However, there is another even more direct experiment you could have run at the Python REPL to see what Python expressions return: just type the expression directly at the REPL and see what it prints back at you. In Python 3:
peter@ToshibaSatellite:~$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> "something"
'something'
And in Python 2: peter@ToshibaSatellite:~$ python
Python 2.7.12 (default, Dec 4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> "something"
'something'
So, in your test function above, the expression "something" does return itself; it just does it inside the function, and that return value then gets thrown away when the function exits, because you didn't return it from the function itself.Lambda, map, reduce, and filter were part of the Python 1.0 release. The actual commit date was Tue Oct 26 17:58:25 1993 +0000:
commit 12d12c5faf4d770160b7975b54e8f9b12694e012
Author: Guido van Rossum <[email protected]>
Date: Tue Oct 26 17:58:25 1993 +0000
* compile.[ch]: support for lambda()
* PROTO.h, mymalloc.h: added #ifdefs for TURBOC and GNUC.
* allobjects.h: added #include "rangeobject.h"
* Grammar: added lambda_input; relaxed syntax for exec.
* bltinmodule.c: added bagof, map, reduce, lambda, xrange.
* tupleobject.[ch]: added resizetuple().
* rangeobject.[ch]: new object type to speed up range operations
(not convinced this is needed!!!)
You can see the commit had its doubts about xrange, but said nothing negative of the functional programming aspects.Van Rossum described that history at https://python-history.blogspot.com/2009/04/origins-of-pytho... . I don't see anything which sounds like "throwing a bone", much less being "explicitly against functional programming" when that discussion occurred.
My understanding is that he wasn't opposed to their inclusion initially but became negative towards them only years later.
See also: map and filter being the only 2 other functions implemented and both of them being less performant than their imperative equivalents; outright denial of any attempt at TCO because "Guido doesn't like recursion".
No, don’t ignore problems of TCO by saying “guys don’t like functional programimg”. Guido cleary states why he doesn’t like it: [1]. Even though TCO is one of the ES6 standard, TCO also is largely denied by JS implementors (Firefox, Chrome, and Edge devs) because of the similar reasons. As a result, Safari is the only browser that supports TCO. [2][3] And Rust team is not eager to introduce TCO [4].
[1]: http://neopythonic.blogspot.com/2009/04/tail-recursion-elimi...
[2]: https://www.chromestatus.com/feature/5516876633341952
We will sometimes optimize for TCO, that issue is that we can’t guarantee it just yet.
But the point is, even with f# syntax, most of the blog post would still apply (needless function calls, non-trivial functions, multiline-unpacking and so on)
I do not agree with some of the premises of this post, but saying that changing lambda syntax will somehow help is just not true.
i wasn't really suggesting changing the syntax would help (although the confusion here is more semantic than syntactic). i was pointing out that in other languages, like in f#, things are much more clear than in python. the section mentioning the name thing is still not clear to me (in python) in terms of what exactly the differences are, and that was my point. that exists a lot in python.
That's what python is doing and why the two are different.
(I don't think a language should track that sort of thing, but that's a different story).
val test1 : x:int -> int
val test2 : x:int -> int
you call them the same way, and they have the same type. a caller has no knowledge of how they were defined because it isn't important. they're identical.Does that mean that test1 == test2 will return true?
Personally, I have found it very useful for debugging that function objects in Python carry their name. That makes it much easier to find out where something is coming from.
There never was a goal in Python development to support all programming paradigms.
How do you distinguish between "design flaw" and "different design goal than what you want"?
EDIT: (Van Rossum's own explanation of why he thinks lambda's design is okay: https://www.artima.com/weblogs/viewpost.jsp?thread=147358 )
The phrase, by the way, is "one obvious way".
The lambda syntax isn't that different from the syntax for defining functions, unless you're referring to the fact that it's different than anonymous functions in other languages.
I don't find the inability to pass around operators to be a hindrance, but the fact that getting into python requires understanding all of these dunder or magic methods is another story.
However, on map, filter, & reduce, I agree with you completely.
One of the worst aspects of python is the extensive use of bad practices, and ignoring functional programming principles is one of the top offenses.
they weren't intended to be great or mind blowing. they were just examples to make the point that in a good language, it's clear what is going on.
the operator thing is an extension of that. in f#, the "infixness" is just a syntax thing. the semantics is that they are functions and can be treated as such. it seems operators are something weird in python.
It seems like a language designed for people who really have no interest in craft of programming, and just use it as a means to an end (note I'm not saying there's anything wrong with this, but if your career is in programming, and you keep that attitude, I'd suggest you find another one or move to management, you're not gonna be happy).
And finding new more effective ways to do common things, new tricks so to speak, is important in keeping the mind engaged.
The tools might not be as important as the end product, but for the person who is always using those tools, being able to improve and customize them to their liking is extremely important.
I guess the difference is a programming language is less a tool than an end product in itself, that needs to be able to be understood and modified by other people. As opposed to say, a plumbers preferred toolset, of which no trace will be left when the next person comes to do the job.
It's kind of funny how much that echos the past criticisms of Java - a language lacking in all kinds of features that frustrate advanced programmers. Yet Python's popularity was in many ways a reaction against Java - perhaps for other reasons.
Yep. Had a coworker like that recently. Loved “simple” code, chock full of mutable data everywhere, where everything was written out a good 3 or 4 times longer than I would have liked to see it.
I call that sort of “simple, explicit” (repetitive) code “My Summer Vacation” code, after a bit in an old Cheech and Chong skit where the highschool kids have to read their essays to the class.
--------------------
Edit: Apparently, there are some people who do like Python the language, and some people who dislike Python the ecosystem. If you want to find a thing, just say it doesn't exist, and it will find you.
but yes, there are lots of libraries. i think people need to take a stance and simply pull those libraries into other languages (which many are already) or simply realize that most are just wrappers around some other language library, which can be easily done in other languages as well.
Don't get me wrong, there's a huge number of packages available and a lot of them are really quality and I have used the language a lot, but good gosh is the packaging a deployment a fucking disaster.
Environments are a 3rd party bolt on, that relies on hacking around with environment variables. There's no distinction between dev dependencies and actual, application dependencies. The packaging/deployment tool has gone through a bunch of different formats/styles and when it comes to deploying your code, you have nothing better than writing a bash script that automates your environment creation, activation and running of the packaging tool (you then just hope that Pip doesn't fail on some bizarre edge).
I beg to differ. I like Python the language. I also like Python the ecosystem.
Can you give a link? I'd be interested to read it.
http://www.gigamonkeys.com/code-quarterly/2011/hal-abelson/
the paragraph he says it in is:
> It’s just a different course. We could have done it in Scheme and I sort of wish we had. And for random reasons we didn’t. But the thing that ties it together—if you had fifteen seconds to describe the whole course—it’s still about abstraction and modularity. The beginning of that course is not very different from the beginning of 6.001 other than you do it in Python. But at that point, where you’re not building interpreters yet, you can pretty much do this stuff in Python. You have to contend with Python’s broken notion of lambda but other than that it’s not really that different.
he mentions it as an aside really, but the overall interview itself is very good. abelson is a treat to listen to.
as explained in the interview, the course changed to python because the course itself changed. they basically killed off the old course and created new courses built around their new degree program structure. the new course hits a lot of different aspects of electrical, computer, and software engineering, many of which heavily use existing libraries, so they seemed to pick python for this.
in my opinion, they could have easily written libraries in another language, so i suspect there were some politics at MIT that lead to the decision to use python.
the fact that creating a function with lambda versus the normal way is different is bonkers. for example, in f# (and other sane languages), the following are identical:
both return: are they really different in python or is it just a weird naming problem? the article isn't explicit on the actual differences other than what is reported by the REPL.also, you can't pass operators as functions in python? in f#, you simply wrap them in parentheses.
i read an interview with hal abelson where he called python's lambda broken. seems so.edit: also, this guy's thoughts on map and filter, in my opinion, show the python community's backwoods thinking regarding functional programming. yes, it seems generator expressions are nice (they are called sequence expressions in f#), but map and filter, even for his simple examples are much more clear. they communicate better what is actually happening. the fact that he never uses map and filter at all and then goes on to basically say map and filter aren't even needed in python says a lot.