8 ms·
One thing that's been key for me is namedtuple (in the collections module). It's immutable like a tuple, but the values can be accessed by name just as if they
by chimeracoder 14y ago
One thing that's been key for me is namedtuple (in the collections module). It's immutable like a tuple, but the values can be accessed by name just as if they were object attributes built with the class keyword. It's great for creating generic functions (think Lisp and CLOS) instead of using Python's prototypical system. And since tuples can contain any objects and functions are objects, you can bind callables like lambdas to those names, which allows you to have 'methods' if you want as well.
That said, the standard library leaves something to be desired for the functional style. It makes sense for object-oriented programming to have non-mutating functions return the result and mutating functions return None (think sorted vs. sort), but this can get rather irritating when you're trying to write in a purely functional paradigm.
Also, am I forgetting my Python, or does it not have a great solution for appending to the front of a list? One thing I love about Lisp is that it's ridiculously easy to write (cons item some-list), or even (cons item1 (cons item2 some-list)). Doing the same thing in Python is irritating, because insert() doesn't return the result list.
...or maybe that's what I deserve for trying to write Lisp-like code in Python, anyway....!
EDIT: As noted in the comments, the '+' operator will suffice here. Though since lists are really arrays and not linked lists, this functional way of thinking will result in horribly inefficient CPython code.
- aeter 14y agoHow about [item] + [some, list]?
- sureshv 14y agoThat works but it's kind of a pain that the natural pythonic syntax: ['a'].extend(some-list) doesn't return a list.
- andylei 14y agothat is not the natural pythonic syntax. for concatenating lists, "+" is standard
- sureshv 14y agoThanks - looks like plus operator concat was in there in the beginning as well: http://docs.python.org/release/1.4/lib/node10.html#SECTION00315000000000000000 http://docs.python.org/release/1.4/lib/node10.html#SECTION00...
- chimeracoder 14y agoHmm, I forgot that '+' was overloaded for lists in Python - nevermind that last statement, then. The rest still holds, though - not all functions have a mutable and immutable counterpart (like sort) and map() returning lists makes them rather unwieldy. I think they fixed this in Python 3, though I'm not sure if it was backported to 2.7.
- andreasvc 14y agoThere's in-place .sort() and the functional sorted(), which has been there since at least 2.6. There's no in-place map, but it would be a one-line function (and you could use map as an in-place operator if you use a function for its side-effects). In the case of + there's the in-place counterpart += (same as extend for lists). So I don't really get your concern, plus mutability is a property of data-structures, not of functions.
- chimeracoder 14y ago> There's no in-place map It's not a matter of in-place mapping, but if I remember correctly, map() returns a generator in Python3, which has the effect of simulating single-traversal and lazy evaluation like Haskell does. > mutability is a property of data-structures, not of functions True, but in a (purely) functional language, if all data structures are immutable and functions are simply mappings of input values to output values with no side-effects, that's inconsequential. We're talking about simulating a functional paradigm within a non-functional language with mutable data structures, so writing functions without side-effects would be more idiomatic - hence the problems with trying to write Python in a functional style.
- gbog 14y agoIf Python were a non-functional language, as you claim, it wouldn't have map reduce and functools. Python is not a purely functional language, it is a multi paradigm language. This difference is the main point here.
- 14y ago
- emiliobumachar 14y agoMaybe there's no way in the standard library, and it may be a valid point that it should be there, but you could trivially define your own 'cons' function and write cons(item, someList)
- TazeTSchnitzel 14y agonamedtuple is awesome, until you realise it works internally by using eval and generating the source code of a class.
- chimeracoder 14y agoAnd Lisps work internally by generating lists and evaluating those, but you don't see me complaining about macros! In all seriousness, though, if I really wanted a functional implementation, I wouldn't be using Python. It's more just nice to know that I can create an object that's immutable and which functions more or less like a CLOS object, so that I can think in that mindset instead. Also, I believe it doesn't come with all of the hidden functions that it would otherwise. In the end, if I really cared, I'd actually write a wrapper around the type() function.
- mattdeboard 14y agonamedtuple is still awesome. The fact that it's eval'ing a string to initialize it doesn't make that any less the case. However, I'll agree that it would be disingenuous to say it's not a little peculiar, and surprising to see the source for it :)
- slig 14y agoWhy does it do that, instead of some other more pythonic way?
- benhoyt 14y agoSee also http://bugs.python.org/issue3974 http://bugs.python.org/issue3974, where someone submits a patch for namedtuple that doesn't use exec. The maintainers reject it as less clear and probably slower. I agree there is "nothing unholy in using exec", though I found this weird at first too.
- samdk 14y agoPython lists are array-backed, Lisp lists are singly-linked lists. Appending to the front of an array list is O(n)--you don't want to do it. Appending to the back is constant time, but is an in-place operation and doesn't return anything, which is less than ideal for FP purposes.
- chimeracoder 14y agoThat's the problem. I can fake a functional paradigm within Python in some settings, but it falls apart at the seams.
- groovy2shoes 14y agoYou can always use 2-tuples to get lists in the Lisp sense. You'd add an item to the head of a list by just pairing it: lst = (2, (3, ())) newlst = (1, lst) Toss in some small helper functions and they become less unwieldy. You could pretty easily write an iterator for processing these lists: class List: def __init__(self, lst): self.cursor = lst def __iter__(self): return self def next(self): if self.cursor == (): raise StopIteration else: head = self.cursor[0] self.cursor = self.cursor[1] return head Then you can do stuff like: >>> for i in List(newlst): ... print i ... 1 2 3 >>> map(lambda x: x + 1, List(newlst)) [2, 3, 4]
- andylei 14y agoif you want to append to fronts and backs of lists, you should use deque: http://docs.python.org/library/collections.html#collections.deque http://docs.python.org/library/collections.html#collections....
- FuManJew 14y agopronounced "deck"
- pjscott 14y agoSo it is a doubly linked list, its name is deque, and its name is pronounced "deck". The levels of indirection here sound kind of like something Lewis Carroll might write.
- algorias 14y agoThe name means double-ended queue. That's the reason behind the strange pronunciation.
- mappu 14y ago'deque' is an irregular abbreviation for double-ended queue, and "deck" is a convenient metaphor for visualising the container - you can put things at either end of a deck of cards. c.f. std::deque<>
- rbonvall 14y agoOne thing I love about Lisp is that it's ridiculously easy to write (cons item some-list), or even (cons item1 (cons item2 some-list)). Iterators can help (and in O(1)): >>> from itertools import chain >>> some_list = range(5) >>> item = 99 >>> a = chain([item], some_list) >>> for x in a: ... print x ... 99 0 1 2 3 4
- gbog 14y agoYes. That's the hole point of the article, and matches very well with my understanding of SICP: functional programming is possible only if you model changing state in streams, which are just called iterators in python. All the fuss about python missing some parts too be really functional seem to have missed the point to me.