a Python person's experience with Ruby

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Sat Dec 8 17:54:39 EST 2007


MonkeeSage a écrit :
> On Dec 8, 12:42 pm, Bruno Desthuilliers
> <bdesth.quelquech... at free.quelquepart.fr> wrote:
> 
>>MonkeeSage a écrit :
>>
>>
>>>On Dec 7, 11:08 pm, Steve Howell <showel... at yahoo.com> wrote:
>>
>>(snip)
>>
>>>> 4) Ruby forces you to explicitly make attributes for
>>>>instance variables.  At first I found this clumsy, but
>>>>I've gotten used to it, and I actually kind of like it
>>>>in certain circumstances.
>>>
>>>4.) Yeah, it's hard when learning ruby, especially if coming from
>>>languages that distinguish between methods and attributes,
>>
>>which is not the case in Python
> 
> 
> It is, I just wasn't absolutely precise (uh-oh, here comes the
> semantics police! -- don't pass GO, don't collect $200, go strait to
> jail!). Python *does* distinguish between instance/class vars and
> instance/class methods. But in ruby no such distinction exists.
> Accessing a "variable" in ruby == calling object.var. I.e., in ruby,
> when you say "blah.x" that translates to "blah.send(:x)", whether :x
> is a "variable" or a "method," since *everything* is a method. The
> call model of ruby is more like smalltalk.

I'm sorry to have to insist: Python doesn't distinguish between methods 
and attributes. Calling a method in Python is really 1/ looking up an 
attribute then 2/ applying the call operator on what the lookup eval'd 
to. As a matter of fact, you can stop at the first step, and you'll have 
a reference to whatever the lookup mechanism yielded for the given 
attribute name on the given object. FWIW, Python's functions are plain 
objects, and when used as attributes are stored in the same place as any 
other attribute.

> 
>>>to get used
>>>to thinking of "a.a" and "a.a=" as method calls and defining accessors
>>>for those methods  (or using one of the attr_* keywords) in the class
>>>body.
>>
>>Python has an equivalent support for computed attributes, using property
>>or a custom descriptors. While it's a bit lower-level than Ruby, it's
>>still quite easy to use and IMHO a bit more powerful.
>>
>>
>>>The equivalent python idiom is something like:
>>
>>>class A:
>>>  __a = "foo"
>>>  def __init__(self):
>>>    self.a = A.__a
>>
>>WTF ???
>>
>>
>>>Which roughly translates to this in ruby:
>>
>>>class A
>>>  attr_accessor :a
>>>  def initialize
>>>    @a = "foo"
>>>  end
>>>end
>>
>>The Python translation of the above Ruby snippet is actually way more
>>simple:
>>
>>class A(object):
>>   def __init__(self):
>>     self.a = "foo"
>>
>  
> Not really. 

Yes, really. Sorry to have to insist, but...

> In ruby an ivar is accessible within the class *only*, but
> not from without (like a mangled python class var), unless you declare
> an accessor (or write the accessor methods yourself).

Your Ruby snippets uses attr_accessor, which gives direct, uncontrolled 
read/write access to the attribute. So I maintain that the *exact* 
semantic equivalent in Python of your Ruby snippet is a plain attribute.

> So my example is
> closer, and is not a WTF, if you know how ruby works.

I know enough about Ruby to understand this snippet, and enough about 
Python to tell your Python example is a WTF.

FWIW, your Python snippet ends up doing the same thing as mine - that 
is, it defines a plain instance attribute named 'a' - but uses a 
reference to class attribute instead of a string literal as the initial 
value of the instance attribute. Since Python strings are immutable, the 
final result is the same wrt/ the instance attribute - it's just overly 
complicated, hence the WTF label.

OTHO, your Python code also defines a class attribute which doesn't 
exist in the Ruby snippet. Mine doesn't imply any class attribute. So my 
Python translation is way closer to the Ruby original !-)

If you what you had in mind was an example of a computed attribute, 
here's the correct code:

class A(object):
   @apply
   def a():
     def fget(self):
       return self._a
     def fset(self, val):
       self._a = val
     return property(**locals())
   def __init__(self):
     self.a = "foo"

Now since we're just getting/setting the attribute, all these 
indirection levels are totally useless, so in such a case we just use a 
plain attribute. So my first exemple (plain attribute) is effectively 
the *exact* semantic equivalent of your Ruby snippet. CQFD.


>>>1.) I also found python's style of method referencing to be a lot more
>>>intuitive than using something like ruby's "m = method('foo');
>>>m.call('bar')" to get a reference to foo() and call it. It's alot
>>>cleaner to say "m = foo; m('bar')", imo. But this goes back to the
>>>omitting parens thing, which makes it impossible to do it that way in
>>>ruby.
>>
>>Yeps. This is where the real and fundamental difference between Ruby and
>>Python becomes evident. Both have support for transparent computed
>>attributes, but the way it's implemented is totally different - in Ruby,
>>by not having a call operator at all (I mean, the parens), in Python by
>>having both an explicit call operator and an explicit protocol for
>>computed attributes (the descriptor protocol). Not to say one is better
>>than the other, but that while both languages have similar features
>>(and, at first look, similar syntaxes), they really have totally
>>different object models.
>  
> Yes and no. I'll leave it at that. If you want to know more, do your
> homework. :P

Hmmm... Sorry, but from this thread and another one here about the 
distinction between attributes and method, I have the strong impression 
you have more homework to do than me - at least wrt/ Python's object 
model. May I suggest you take a look at the doc about the lookup 
mechanism, the descriptor protocol and the call operator ?-)

>>>Though, ruby does allow some interesting things by having it
>>>that way, e.g., letting you substitute a Proc object (e.g., a block or
>>>lambda) for a method reference transparently.
>>
>>Care to give an example ? I don't have enough working experience with
>>Ruby to be sure I understand what you mean here.
> 
> 
> For example, any place expecting a foo (method reference), can be
> exchanged with a { "bar" } block or a lambda { "baz" }.

You mean that a method reference, a block and a lambda can all be called 
? Yes, fine. Now I don't really see how it's very different from Python 
(except of course for the fact that Python doesn't have blocks).

Sorry to be dump, but a more concrete exemple might help here. I mean, a 
  code snippet.

Regards,



More information about the Python-list mailing list