Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Hmmm, I don't think this article accurately represents how people write python since ~2005. I'm biased because I use python every day, but there's a big objective mistake.

> Ruby flips the script, giving the objects deeper customizability.

Not really, because python allows you to do things the Ruby way, but I'm not sure the reverse is true.

    class Stuff:
      def __init__(self):
        self.a = [1, 2, 3, 4]

      def __iter__(self):
        for item in self.a:
          yield item
and you can write it more simply in this case.

    def Stuff():
      a = [1, 2, 3, 4]
      for item in a:
        yield item
What about the select and map example?

    class Stuff:
      def __init__(self):
        self.a = [1, 2, 3, 4]

      def __iter__(self):
        for item in self.a:
          yield item

      def map(self, f):
        for item in self.a:
          yield f(item)
Which can be used just like the ruby example, with syntax of similar ugliness.

    print(Stuff().map(lambda item: item))
I think I could come up with a python example that maps 1:1 onto pretty much any ruby example, but I don't think it's possible in general to find ruby examples that map onto more complicated python.


Author here! Very true, though I was trying to focus on idiomatic python that pushes logic into for loops, list comprehensions, etc w/ composable iterators through tools like those found in itertools (zip, etc...)

Since Python doesn't have Ruby's blocks, you have to define a non-trivial function as a free function, so it's less likely you'll do this. (Python's lambda's are far more limited than Ruby's blocks.)

You can also trick Ruby to return a new value every time a method is called for iteration, but again my focus on what I see as idiomatic in the two languages


Your Python example is far from idiomatic, though. If a Python programmer were forced to write `Stuff`, they'd write something like:

    class Stuff:
        def __init__(self):
            self.a_list = [1,2,3,4]
        def __iter__(self):
            return iter(self.a_list)
--- or do what the other person did, and make `__iter__` a generator, which isn't necessary in this case but is much more flexible.


Yes, but if you’re new to Python you’re not going to grok this.


> think I could come up with a python example that maps 1:1

My take on it:

    class Stuff:
        def __init__(self):
            self._list = [1, 2, 3, 4]
        
        @property
        def each(self):
            for el in self._list:
                yield el
    
    for item in Stuff().each:
        print(item)
It's even less verbose than the Ruby equivalent in the original article, thanks to the indentation-defined blocks.


AFAIK, there is no reason to use the form “for el in self._list: yield el”, unless you are running Python 3.2 or older.

Why not:

  each = self._list
Or, if you need to be able to re-assign self._list to a new object:

  @property
  def each(self):
    return self._list
Or, if you for some reason need it to return an iterator:

  @property
  def each(self):
    return iter(self._list)
Or, if you really want it to be a generator function:

  @property
  def each(self):
    yield from self._list




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: