Python Ruby Attr Comparison

( see also: PythonRubyInitializer )

Honest questions: is Python dynamic enough to be able to do things like Ruby's attr_accessor? Or the RubySingleton module?

I'm too new to Python to answer your questions with much authority, but see PythonSingleton for some discussion of singletons. Re:attr_accessor, can you give a little code snippet in Ruby that illustrates something you'd like Python to do? Thanks. --SteveHowell

Sure, I'll give you the standard example. :) The following two definitions of the class Point are completely equivalent:

class Point
   attr_accessor :x, :y
end

class Point def x @x end def x=(aNumber) @x = aNumber end def y @y end def y=(aNumber) @y = aNumber end end

Some explanation:

Of course, this is a pretty small thing, and in Python instance variables are all public anyway, so I couldn't possibly be arguing that having attr_accessor around is such a big deal. :) I think my point is that Ruby makes it really easy to work at the meta level like this - and I've had trouble doing similar things in Python.

No, that doesn't sound quite right. Are there any Ruby people out there who know what my point is? (Maybe my point is that I don't know Python well enough. ;)

The answer is here: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/157768 -- AnonymousDonor

getattr, setattr

See "3.3.2 Customizing attribute access" in Python Reference Manual. Not sure it's quite what you're looking for. -- SteveHowell

getattr and setattr are not quite what the original poster was asking about. In the Ruby example, attr_accessor actually creates new methods "on the fly" to get and set the instance variables inside the class. These new methods are not magic (as are getattr/setattr), and could be written by hand. But as the example shows, the attr_accessor is concise and direct, and shows the intention much better than the long hand version. This is an example of metaprogramming. Other examples of metaprogramming in Ruby include...


[sorry, Singleton stuff still snaggled in here, can be refactored elsewhere, maybe PythonSingleton?]


Python doesn't impose great rigor on attributes. The basic rule is you can't use an attribute until you assign it something.

Having said that, you might still want to have some way to make your attributes explicit.

    # Say you want your class to have attributes x and y.  Here is the 
    # most direct approach in Python.

class Point: def __init__(self): self.x = None self.y = None

p = Point() p.x = 3 print p.x print p.y # print p.foo # would throw exception p.foo = 5 # Python will let you add attributes on the fly

# It's kind of tedious to initialize a bunch of attributes to None, # though. class Rectangle: def __init__(self): self.attribs(['top', 'bottom', 'left', 'right'])

def attribs(self, attribs): for a in attribs: self.__dict__[a] = None

r = Rectangle() r.top = 5 print r.bottom # print r.color # this would fail

# You could then refactor out the attribs function

class Attribs: def attribs(self, attribs): for a in attribs: self.__dict__[a] = None

class Employee(Attribs): def __init__(self): self.attribs(['name', 'phone', 'fax'])

emp = Employee() emp.name = 'Steve' print emp.name print emp.phone # print emp.salary # bad

# But I still prefer the explicit way:

class Employee: def __init__(self): self.name = None self.phone = None self.salary = None

print emp.name # print emp.salary # bad

Of course, all of these classes are kind of dull. A more interesting problem might uncover more interesting introspection/metaprogramming techniques in Python.

-- SteveHowell


Here's a Python inversion of this idea: using attribute access to call functions

  import time

class Props: """ automatic getters and setters """ def __getattr__(self, name): return getattr(self, "get_"+name)() # possibly throws attribute error

def __setattr__(self, name, value): x = getattr(self, "set_"+name, None) if x: x(value) else: self.__dict__[name] = value

class T(Props): def __init__(self): self._count = 0 self._mark = 0 def get_time(self): return time.asctime(time.localtime(time.time())) def get_mark(self): return self._mark def set_mark(self, value): self._count = self._count + 1 self._mark = str(self._count)+": "+str(value)

t = T() print t.time time.sleep(1) print t.time t.mark = "first" print t.mark t.mark = "second" print t.mark

-- DirckBlaskey

Very slick, Dirck. One thing I like about Python Programmers is they tend to answer questions with code, not theory. -- SteveHowell


Although interesting examples, I think the original poster's question is addressing a subtly different issue. The question is only superficially about attributes. Attributes were used as an example, but the issue goes deeper. The attr_accessor command (and its bretheren attr_reader and attr_writer) actually creates/writes new methods for you. This makes attr_accessor an abbreviation for writing out the get/set methods by long hand.

Here's how the example might look in Python. Please excuse my Python syntax, I'm not a frequent Python user ...

  class Point:
    def __init__(self):
      self.__x = 0
      self.__y = 0
    create_get_set_methods_for("x", "y")

p = Point() p.set_x(10) p.set_y(20) print p.get_x(), p.get_y()

I think the original poster's question is along the lines ... Can you create commands (such as create_get_set_methods_for) that can dynamically modify the class being defined?

I'm suspect this is no problem in Python, but am not familiar enough with the language to know for sure. -- JimWeirich


As someone mentioned earlier, my recipe (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/157768) was designed for this problem. I saw Ruby's attr_reader, attr_writer, attr_accessor methods and wanted something similar in Python. I wanted to be able to automate the creation of get/set/del methods and I didn't want to bother initializing the attributes associated with those methods in the class' __init__() method. The recipe allows code like this:

from attribute import *

class MyClass(object):

    readable(foo=1, bar=2) 
    writable(fro=3, boz=4)
    attribute(baz=5)

Which is very similar, I think to Ruby's

class MyClass

    attr_reader :foo, :bar
    attr_writer :fro, :boz
    attr_accessor :baz
end

The main difference being that the Python version takes an initial value for each attribute, so that the attributes do not have to be initialized manually in the class' __init__().

To make things clear, the above Python code is equivalent to the following:

class MyClass(object):

    def __init__(self): 
        self.__foo = 1
        self.__bar = 2
        self.__fro = 3
        self.__boz = 4
        self.__baz = 5

def get_foo(self): return self.__foo def get_bar(self): return self.__bar def set_fro(self, value): self.__fro = value def set_boz(self, value): self.__boz = value def get_baz(self): return self.__baz def set_baz(self, value): self.__baz = value def del_baz(self): del self.__baz

Which, admittedly, is long, repetitive code. That's why I wanted to replicate Ruby's way - to avoid this type of boiler-plating.

Later on, I found a need to combine simple and specific property creation, so I made this recipe: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252180. A similar idea, but with a bit more flexibity.

Oh, and there are several other implementations of this idea - many of which use metaclass programming. Those may also be of interest.

-- Sean Ross


Thanks for your patience, maybe this is closer.

First, I declare a class that lets you sort of make a new "get" function on the fly. You pass in the parent class and the name of the field that you want Get.get to, uh, get, and then Get.get will return the value of that class's field. Sort of like a closure, I guess.

    class Get:
        def __init__(self, parent, name):
            self.name = name
            self.parent = parent

def get(self): return getattr(self.parent, self.name)

Next, I create a class that allows you to take a list like ['bar', 'foo'] and dynamically create get_bar and get_foo functions. We don't really define a new function each time, though; we instantiate an object of the Get class that specializes the Get.get function for a particular field name.

    class Dynamic:
        def create_getters(self, names):
            for name in names:
                setattr(self, 'get_'+name, Get(self, name).get)

Now things gets less complicated, I hope. Once the Dynamic class is declared, any class can inherit from it and call create_getters on the fields that it wants getters for.

    class Point(Dynamic):
        def __init__(self):
            self.x = 0
            self.y = 0
            self.z = 0 
            self.create_getters(['x', 'y'])

p = Point() p.x = 17 print p.get_x() print p.get_y()

[Even though get_x() and get_y() are created by the superclass method, they are still available to the subclass.]

I have to admit that it was awkward to create a function on the fly, until I thought of using the Get class. It would be interesting to extend this code to have data members whose writability could be toggled by a constructor. Not sure I'd want to maintain such code, but it would be a fun exercise.

-- SteveHowell


You beat me to it.

Here's another example that adds the attributes to the class instead of the instance:

This example is very similar to Steve's, with subtle differences.

We need the new module to create instance methods on the fly

  import new

The Getter class is functionally the same as Steve's, except that the instance is passed in at 'get' time, not at '__init__' time. (I removed the __call__ overloading to make the example a bit clearer.)

  class Getter:
      def __init__(self, name):
          self.name = name
      def get(self, instance):
          return getattr(instance, self.name)

Again, very similar to Steve's. Using an implied argument list (*args), instead of an explicit list. Also, creating new instance methods and installing them in the class, instead of attaching them to the instance.

The new.instancemethod is required due to binding mechanisms in Python. Python has to know that a function is bound to a class in order to use it as a method. Python can also bind methods to an instance to produce a 'callable'. In other words, something like this:

 #        f = instance.method
 #        f()      # call

What's interesting about this usage: Below we create a bound callable with our baggage (the attribute name we're interested in), which in turn is re-bound to the Class. It's very interesting that Python can cascade bound callables this way. Once the method is bound to the class, an implicit argument is the instance it's invoked on. There's already an implicit argument of the Getter instance already bound, so the instance we're invoking the get_X on becomes the second argument to the get method above.

  def create_getters(klass, *args):
      for arg in args:
          setattr(klass, "get_"+arg, new.instancemethod(Getter(arg).get,None,klass))

Just a silly example class, I guess it could be a Point

  class Point:
      def __init__(self, x, y):
          self.x = x
          self.y = y

Another subtlety here: The name of the class isn't a valid reference until after the class is defined. The call that installs the getters isn't part of the class definition, it happens after.

  create_getters(Point, "x", "y")

Demonstrate the created methods

  p = Point(1,2)
  print p.get_x()
  print p.get_y()

I think the point of these examples is that the Python meta-model is fairly accessible from within Python. The new module exposes some important functionality, and there are some other lower-level modules for even more brutality (e.g. codeop or bytecodehacks) not that it's necessary (mostly).

-- DirckBlaskey


Yes! Thank you. Both versions are closer to what (I suspect) the original poster was asking. If Steve and Dirck would like to add commentary to their examples, I would certainly appreciate it. I follow the generally outline, but I'm afraid I'm not following all the details.

It looks to me that Steve's version creates the methods on each object as they are allocated. As a result, each object has a different instance of the "get" method. Is that correct? Dirck's method adds the methods directly to the class (again, if I read it correctly).

Since this page is comparing Ruby and Python, I'll provide the Ruby version of the same thing. attr_reader is built-into the language, but it is possible to define a create_getters (which does much the same thing) as follows...

  class Module                    # [A]
    def create_getters(*ids)      # [B]
      for id in ids
        module_eval %{            # [C]
          def get_#{id.id2name}
            @#{id.id2name}
          end
        }
      end
    end
  end

class Point create_getters :x, :y # [D] def initialize(new_x, new_y) @x = new_x @y = new_y end end

p = Point.new(17,5) puts p.get_x # prints '17' puts p.get_y # prints '5'

Comments: -- JimWeirich


Jim,

Thanks for the Ruby example. I have added comments above to my Python example. Your interpretation of it was correct. -- SteveHowell

I've added some comments to my Python example, as well. I learned some interesting things from writing it. -- DirckBlaskey


Yes, those last two Python versions are pretty close to what I wanted. I still think the Ruby version is prettier :), but I'm happy. Thanks, Python people. --AdamSpitz

The Ruby example comparison is interesting because it's actually compiling new code. The Python examples aren't - though they could be, but it's not necessary for this case. -- DirckBlaskey

I think it's interesting that you chose the words "not necessary." ;) I think it's a cultural issue - Python culture is centered around readability, and Ruby culture is centered around flexibility. It sounds to me like Python culture prefers to use ordinary classes (since everybody knows how those work) instead of dynamically creating new code (since that isn't done very often). In Ruby culture, if using eval() is the most natural way to approach the task, then it should be approached that way.

(Of course, I've just been assuming that the eval() way is more natural. It seems to me that if the task is, "dynamically generate accessors," then the most natural way to approach it is to dynamically construct a string containing an accessor method. Maybe we disagree?)

In any case, I'm pretty impressed with Python's flexibility, and I hope we can manage to persuade you that Ruby is pretty readable. Maybe we should all just go pick on the Java people. ;)

--AdamSpitz

Well, when I said "not necessary" I was referring strictly to the Python implementation - that, for me, it makes sense to do it the way presented, and it seems straight-forward enough. It could be implemented as building strings and compiling them, but that approach in Python would not be quite as simple as it is in the Ruby example.

I haven't been exposed to a lot of Ruby, but what I've seen so far is interesting. And yet... I have a distaste for Perl, and Ruby has a Perl heritage, and might be said, at least in jest, to have the 'clarity of Perl and brevity of Python'. If I knew it better, I'm sure I would have a different opinion - but for the time being I'm happy with Python, and it's powerful enough without taking a kitchen-sink approach to the language itself, the way Perl seems to. Maybe in the future I will get more exposure to Ruby.

--DirckBlaskey

Ruby has a lot of heritages. :) Perl's just the most obvious one, because a lot of Ruby examples are intended to appeal to Perl programmers, because Python people are a lot harder to convert. ;) --AS (See PythonVsRubyHeritageAndPhilosophy?)

I was a happy Perl programmer for a long time, and I resisted Python. Now I am a happy Python programmer resisting Ruby. I do like the concept of metaprogramming. All three languages seem to converge on good features, while still keeping some of their own character.

-- SteveHowell

How about this Python solution? I'm not sure if using exec counts as evil, though; and of course it's not as elegant as some of the above solutions.

  def attr_accessor(*args):
      accessors = ""
      for attr in args:
          accessors += "def get_" + attr + "(self):\n"
          accessors += "    return self." + attr + "\n"
          accessors += "def set_" + attr + "(self, value):\n"
          accessors += "    self." + attr + " = value\n"
      return accessors

class Point: exec attr_accessor("x", "y")

origin = Point() origin.set_x(0) origin.set_y(0) print origin.get_x(), origin.get_y()

It can be extended to attr_reader and attr_writer fairly easily.


See also http://www.python.org/2.2/descrintro.html under the section named "Properties: attributes managed by get/set methods". It describes a new feature introduced in Python 2.2. In "new-style classes", there is an easy way to "trap" attribute access - in other words, it's very easy to make all code which accesses "myInstance.x" actually invoke the method "myInstance.get_x()", or "myInstance.set_x()" as appropriate. If your goal were to create accessors, this would be a far superior way of achieving it. However, I don't think it obsceletes the above discussion, because the discussion was never intended to be about creating accessors, it was about the inherent levels of flexibilities in the two languages and how these are achieved, with accessors being just an illustration. -- MichaelChermside


See PythonVsRuby

CategoryRuby CategoryPython CategoryProgrammingLanguageComparisons


EditText of this page (last edited July 20, 2007) or FindPage with title or text search