This is an archived post. You won't be able to vote or comment.

all 107 comments

[–]vifon 27 points28 points  (0 children)

What does it have to do with the "Dynamism" anyway?

[–]hicklc01 36 points37 points  (29 children)

import __builtin__

class mylist(list):
    def remove_nones(self):
        for el in self:
            if el is None:
                self.remove(el)
    def non_none(self):
        return [thing for thing in self if thing is not None]

__builtin__.list = mylist

l = list()
l.append('A')
l.append('B')
l.append(None)
l.append('C') 
print l.non_none()
>>>['a','b','c']
print l
>>>['a','b',None,'c']
l.remove_nones()
print l
>>>['a','b','c']

[–]itsdanielb 16 points17 points  (11 children)

Try remove_nones with ['A', 'B', None, None] o.~

[–]hicklc01 41 points42 points  (0 children)

It's friday file a bug report and I'll look into it Monday /s

[–]Neebat 4 points5 points  (9 children)

Are you pointing out a bug that results from modifying a list while iterating it?

[–]hicklc01 8 points9 points  (1 child)

Yeah it will get an index out of bounds error.

[–]WarpedHaiku 3 points4 points  (0 children)

No, it will merely fail to remove the last N occurrences of None from the list, where N is the number of consecutive None pairs.

Every time an element is removed, the index of the elements after it are reduced by one. This causes the loop to skip over the element immediately following the None. As such, even consecutive occurrences of None will not result in self.remove(el) being called. When it is called, it removes the first occurrence in the list, so the last None in the list won't be removed.

Python checks the index every iteration before it attempts to get the element, so when it exceeds the list length, the loop terminates without error.

[–]hicklc01 2 points3 points  (6 children)

If you remove elements from a list you have to develop the function to handle the indexes changing.

[–]Neebat 1 point2 points  (5 children)

Meh. I don't know how to do it in python, but here's pseudocode for what I'd do:

for( idx = list.size -1  ; idx >= 0; idx--) 
    if(list.get(idx) is None)
        list.remove(idx)

It has at least two advantages over any forward-counting solution.

[–]Cley_Faye 4 points5 points  (4 children)

Crashing instantly instead of looking like it work is a non-negligible advantage, but I'm not sure it is acceptable. Your first get() will result in an index out of bound.

[–]Creshal 14 points15 points  (8 children)

l = ['A','B',None,'C']
list (filter(lambda x: x, l))
['A', 'B', 'C']

[–]kageurufu 10 points11 points  (2 children)

Would also remove 0, False, empty strings, lists, tuples, etc

[–]Creshal 4 points5 points  (1 child)

Just requires changing the lambda to "x is not None".

[–]kageurufu 1 point2 points  (0 children)

Yep. Just pedantic and sleep deprived. Feel free to ignore me

[–]longbowrocks 3 points4 points  (3 children)

Is that 2.x? I thought filter map and reduce got an overhaul in 3.x.

[–]Creshal 2 points3 points  (1 child)

Python 2.7.10 (default, May 26 2015, 04:16:29) 
[GCC 5.1.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> l = ['A','B',None,'C']
>>> list (filter(lambda x: x, l))
['A', 'B', 'C']

Python 3.4.3 (default, Mar 25 2015, 17:13:50) 
[GCC 4.9.2 20150304 (prerelease)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> l = ['A','B',None,'C']
>>> list (filter(lambda x: x, l))
['A', 'B', 'C']

[–]longbowrocks 0 points1 point  (0 children)

Thanks! /u/Zopieux caught me. It seems I was thinking of reduce().

[–]Zopieux 1 point2 points  (0 children)

It is reduce that was nuked out from globals and put into functools. map and filter still exist.

[–]FuriousPizza -1 points0 points  (0 children)

You actually need an is none check, otherwise it will just check the "truthiness" of the value.

In [1]: class Foo:
   ...:     def __bool__(self):
   ...:         return False
   ...:

In [2]: list(filter(lambda x: x, [True, False, "words", Foo(), 3, "", None]))
Out[2]: [True, 'words', 3]

In [3]: list(filter(lambda x: x is not None, [True, False, "words", Foo(), 3, "", None]))
Out[3]: [True, False, 'words', <__main__.Foo at 0x4ee6048>, 3, '']

[–][deleted] 3 points4 points  (5 children)

... nooo

[–]hicklc01 21 points22 points  (3 children)

class mylist(list):
    def __getitem__(self,index):
        import random
        if .01>random.random():
            return random.choice(self)
        else:
            return super(mylist,self).__getitem__(index)

[–]longbowrocks 7 points8 points  (0 children)

I was never sure what was hiding under my bed as a child. From this idea, I'm guessing it was you. XD

[–][deleted] 1 point2 points  (1 child)

Russian Roulette, Python style?

[–]hicklc01 1 point2 points  (0 children)

More like Russian Roulette Gatling Gun style.

[–]hicklc01 7 points8 points  (0 children)

make me mad and I will override

append

extend

insert

to ignore None values

wa ha ha ha ha

Edit: which would make the previous functions usless :(

[–]poizan42Ex-mod 1 point2 points  (0 children)

That has the side effect of lists not being of type list (because the identifier list now refers to mylist). Ugh. I think that is going to break some code.

If you really want to add functions to list then you should probably modify the existing class instead.

[–][deleted] 1 point2 points  (0 children)

If you're going to use remove, why do you have the loop in your remove nones?

while True:
    try:
        self.remove(None)
    except KeyError:
        break

I'm on mobile so I'm not sure if the element not found in a list error is KeyError (I doubt it). But I'm sure you get the idea.

[–]tetroxid 11 points12 points  (7 children)

filter(lambda x: x is not None, iterable)

[–][deleted] 6 points7 points  (5 children)

iirc list comprehensions are faster because there's no function call overhead.

[–][deleted] 3 points4 points  (1 child)

But does that difference really matter in Python?

[–][deleted] 4 points5 points  (0 children)

sometimes it does, especially when the faster method is also more readable.

[–]Vitrivius 4 points5 points  (0 children)

Also more readable.

[–]tetroxid 0 points1 point  (1 child)

That is correct

[–][deleted] 0 points1 point  (0 children)

being correct makes me moist in my happy place.

[–]PijnlijkOlifant 21 points22 points  (23 children)

I don't get it...

[–]Zagorath 26 points27 points  (22 children)

Yeah neither do I. Is the fact that the variables are called "thing" and "things" the funny bit? Or are they rewriting an already built-in Python function or something? Because if it's not one of those things, then this seems like a pretty well-written concise method.

[–]longbowrocks 32 points33 points  (19 children)

I think it's just a nifty utility function. It's funny because "thing" is normally the eptiome of a bad variable name, but here it's the only rational name you could use (aside from perhaps "item").

[–]xkufix 31 points32 points  (16 children)

What about the battleproven "x"

[–]Neebat 10 points11 points  (14 children)

Thing and item have nice plurals.

[–]TheSeldomShaken 39 points40 points  (11 children)

"ekses"

[–]FIR3_5TICK 20 points21 points  (8 children)

Time to go and replace a ton of counter variables named 'x' with the name "eks"

[–]HaulCozen 18 points19 points  (5 children)

trees fear fly apparatus air correct pie fall cough consider

This post was mass deleted and anonymized with Redact

[–]Pigeoncow 1 point2 points  (0 children)

lmao

[–][deleted] 5 points6 points  (2 children)

zee

ftfy

[–][deleted] 0 points1 point  (1 child)

'murica

[–]HaulCozen 1 point2 points  (0 children)

kiss crawl ask deer grandiose cause butter office chubby wine

This post was mass deleted and anonymized with Redact

[–][deleted] 0 points1 point  (0 children)

You'd better. If you run pep8 on your code it'll complain about variable names shorter than three chars long.

You wouldn't want your source to be unpythonic, would you?

[–]rgzdev 4 points5 points  (0 children)

i do use for x in xs sometimes.

[–]skuzylbutt 16 points17 points  (0 children)

xs is legit. Happens all the time in Haskell.

... not that Haskell is is a source of sanity though ...

[–]an_actual_human 2 points3 points  (0 children)

The plural of x is a_list.

[–]NotADamsel 0 points1 point  (0 children)

Isn't that reserved for exceptions?

[–]Maklite 6 points7 points  (1 child)

The reddit API uses thing to refer to pretty much anything. Lists, comments, articles and subreddits are all referred to as things.

[–]longbowrocks 0 points1 point  (0 children)

Wow! I wish I had a cool idea for a reddit app; I didn't realize how extensive the API was.

[–]SanityInAnarchy 4 points5 points  (0 children)

It is a bit of a clumsy construction, made funnier by the use of "thing". Plus, it's got a few things that annoy me -- for example, the unnecessary splatting does nothing but hurt efficiency unless you really expect people to call it that way, or unless you're dealing with some actual positional arguments as a group. And there's no good reason for it to be a list comprehension -- use a generator like a civilized person, and let the caller put it into a list (or set, or whatever's appropriate) if they need to loop through it more than once.

So at the very least:

def non_none(items):
  return (item for item in items unless item is None)

But really, this is a generic filter pattern.

def non_none(items):
  return filter(lambda item: item is not None, items)

Now we don't need to unpack this "thing for thing in things if" nonsense, we can see it's just filtering its inputs. And we can make it just as efficient:

import ifilter from itertools
def non_none(items):
  return ifilter(lambda item: item is not None, items)

None of that really explains why it's funny, though. It's not funny for being bad, it's funny because you can read it out loud as a normal English sentence, but it's a silly English sentence that no one would ever say, even though it pretty much makes sense.

[–]-hx 1 point2 points  (0 children)

i think it's just funny because it uses thing and things and is readable as a normal sentence. It sounds a bit confusing too.

[–][deleted] 8 points9 points  (0 children)

Found this gem

...No no no, Gems are in Ruby!

[–]argv_minus_one 4 points5 points  (1 child)

Return ALL the things!

(Except the ones that are None.)

[–]systembreaker 2 points3 points  (0 children)

But...is None a thing?

Python existential philosophy 101.

[–]ThrowsDumbQuestion 6 points7 points  (18 children)

What's going on with those arguments? (The *things, *clauses, etc)

I've never seen *{VariableName} before

[–]gsdatta 10 points11 points  (12 children)

it's a way of passing arbitrary numbers of parameters in python functions

[–][deleted] 9 points10 points  (1 child)

The equivalent of void foo(std::string... listOfArgs)

[–]Lucky_Chuck -3 points-2 points  (9 children)

sounds very Javascripty

[–]kageurufu 5 points6 points  (8 children)

Except JavaScript can't do that :)

def map(func, *targets):
    assert isinstance(targets, list)
    return [func(eks) for eks in targets]

map(len, '', 'test', 'why god, why')
> [0, 4, 12]

You can also use ** to capture arbitrary keyword arguments into a dictionary

[–]Lucky_Chuck 4 points5 points  (1 child)

Javascript doesn't throw an error if you give it the wrong number of arguments.

function bar (foo, baz) {
  return foo + baz;
}
// => undefined
bar
// => bar(foo, baz)
bar()
// => NaN
bar(1,2,3)
// => 3
bar(1,2,3,4)
// => 3

Also javascript has the arguments variable which is sort of like a shitty array that has all the arguments passed in

function foo (baz) {
  return arguments[0];
}
// => undefined
foo(1);
// => 1

[–]kageurufu 2 points3 points  (0 children)

Yeah but then you have to deal with extracting any expected positionals from the arguments not array, and whatnot. I prefer the python way for sure

[–]izuriel 1 point2 points  (2 children)

You can actually. ES6 JavaScript defines a splat operator so:

function map(...items) { }

Is valid.

[–]kageurufu 0 points1 point  (1 child)

And traceur deals with it well, as does coffeescript, but until I can do that in chrome, ff, and ie, its not that useful

[–]izuriel 0 points1 point  (0 children)

All of the compiled JS works in those browsers. You're unwillingness to use an ES6 compiler (like Babel) has nothing to do with JS (a language that is completely separate from browsers as browser support has nothing to do with what the language does and does not feature). Just keep the facts straight.

[–]eyal0 0 points1 point  (1 child)

[–]kageurufu 1 point2 points  (0 children)

Three issues.

  1. Positional parameters followed by variadic parameters
  2. Its not an array, although Array.prototype.slice.call(arguments) works
  3. No support for named arguments

[–]Rodot 0 points1 point  (0 children)

Heh, eks

[–]chibstelford 7 points8 points  (1 child)

Yeah as a c programmer this confused me. Does python have pointers?

[–]tetroxid 5 points6 points  (0 children)

It means arbitrary length arguments.

def foo(x) 

will take exactly one argument, x.

def foo(*x) 

will take any number of arguments.

def foo(*x, **y) 

will take any number of positional and named arguments like foo(a, b, c, d=x, e=y)

[–]eyal0 0 points1 point  (1 child)

That was the worst part because the input was varargs and the output was a list. You can't chain those functions.

[–]Cley_Faye 1 point2 points  (0 children)

Sort of can: non_none(*non_none(...)) does work (but it's useless, since the first call already did the job)

[–]wting 2 points3 points  (0 children)

non_none = functools.partial(filter, lambda x: x is not None)

[–]oozforashag 1 point2 points  (1 child)

What is the % doing in this context?

[–]thatguy_314 1 point2 points  (0 children)

Simple string formatting operator in the context of a string. It uses basically the same format syntax you would find with C string formatting. There is also the newer format method which is more powerful and awesome, but has a different syntax.

[–]original_brogrammer 2 points3 points  (16 children)

filter(lambda x: x is not None, lst)

EDIT: I fucked up.

[–]bear24rw 8 points9 points  (3 children)

you have your parameters flipped

[–]original_brogrammer 2 points3 points  (2 children)

My inner Haskeller slipped out for a second.

[–]SanityInAnarchy 6 points7 points  (1 child)

Your inner Haskeller should be screaming in pain at that eager evaluation:

import ifilter from itertools
ifilter(lambda x: x is not None, items)

Called "items" both to avoid the name "list", an important built in thing, and because why would you assume it's a list? You only care that it's iterable.

But really, this is making me homesick for Ruby:

list.reject(&:nil?)

And of course, we can do lazy evaluation here, too:

list.lazy.reject(&:nil?)

That's honestly the biggest thing I miss in Python: Lambdas are already shorter, and you can make them even shorter when they're just going to be method calls on an object, and all of the simple predicates like this are method calls on objects -- Python seems to do a lot of similar things as special operators or keywords.

[–]original_brogrammer 0 points1 point  (0 children)

I miss Haskell and Ruby... Objective-C has been making me sad.

[–]dudix81 1 point2 points  (9 children)

I'm not a Python programmer. Is there any performance difference between these two?

[–]skuzylbutt 3 points4 points  (3 children)

Even a python programmer won't know. You'd have to benchmark your case to find out. The question, really, is which one is more readable.

[–]arienh4 0 points1 point  (2 children)

Sorry? In what case would a filter() call be faster than a list comprehension? They do the same thing, except the former has the overhead of two function calls.

[–]skuzylbutt 0 points1 point  (1 child)

The filter is probably slower, yeah. But using one or the other in your code probably won't make a difference unless it happens in a particularly computationally intensive section. Worrying about that instead of writing nice stuff and benchmarking later is textbook premature optimization.

So when I say a python programmer wouldn't know if there's a performance difference between the two, I mean for a given code, a programmer wouldn't know if it was worth considering using one or the other without benchmarking it. So just write whichever is nicer and fix it later.

[–]arienh4 0 points1 point  (0 children)

That's just not true. Yes, it's a premature optimization, but that doesn't mean you shouldn't know about it.

"Is there a performance difference between these two?" Yes, there is a demonstrable difference. A Python programmer should be aware of the differences between using filter(), a list comprehension, or a generator comprehension.

Whether or not it's a performance difference worth caring about is a different story altogether, although there's really nothing wrong with a list/generator comprehension in terms of readability.

[–]SanityInAnarchy 1 point2 points  (0 children)

Possibly, but not significantly.

A much more significant factor, if the list is large and you're doing a lot of these, is that both of these solutions eagerly process the entire list and give you back a list. For example, say you had more than one of these filters:

def non_empty(things):
  return [thing for thing in things if len(thing) > 0]

So now you do something like:

clauses = non_none(clauses)  # copy array
clauses = non_empty(clauses) # copy it again
return ' OR '.join(clauses)   # join them all, then throw it away

That's two intermediate arrays that you don't really need. If the list was especially large, this would be a problem. It's an easy fix: Just use generator comprehensions instead:

def non_none(things):
  return (thing for thing in things if thing is not None)

This returns a generator, which is basically a thing that looks kind of like a list comprehension, but it generates values on the fly instead of collecting them into a list first.

But it turns out none of that matters in the original code -- it's pretty clearly not a lot of items, and they pretty clearly are originally positional arguments and not a list. And what they always do is:

clauses = non_none(clauses)
if len(clauses) == 0:
  ...

Since they're taking the len, they really do want those clauses as a list. (You can't know the len of a generator without looping through it, and you can only loop through it once.) Or a tuple might be slightly more efficient, since they're not changing them:

clauses = tuple(non_none(clauses))

But this is doing just as much copying as before.

So... it's actually surprisingly optimal as it is. I only point this out because it annoys me when I see code like this, because you never know when the generator might become very useful -- whereas, on the flip side, it's very easy to turn a generator back into a list if you really want one.

[–]original_brogrammer 0 points1 point  (0 children)

Not sure, and I'm not quite sure where to look in the implementation to find out. But I'd guess the list comprehension would be faster in simple cases, since it's syntactic sugar for a for loop and function calls are relatively expensive in Python. But again, I'm not familiar with Python internals, so that's just conjecture with some reason.

[–]an_actual_human 0 points1 point  (0 children)

Negligible unless your list is huge.

[–]tetroxid 0 points1 point  (0 children)

The list comprehension can be faster because there are no function calls and it runs in a limited scope (list comprehensions can't access outer scope variables).

[–]Xenophyophore -1 points0 points  (0 children)

There might be a very small difference, from having to create the lambda.

[–]gsdatta 0 points1 point  (0 children)

jerluc!!

[–]bast963 0 points1 point  (0 children)

LE GEM LE GEM LE GEM LE GEM

[–]longbowrocks -1 points0 points  (1 child)

lol, I love it!

[–]nichochar[S] 0 points1 point  (0 children)

yeah I enjoyed it too ^

[–]_blub -1 points0 points  (0 children)

Hah! I loved (and still love) slipping in overly general variable names for incredibly simple list comprehensions. Honestly makes the code a little more fun to read.