3

How can you emulate assignment operator overloading in Python? For example...

class Example(object):

    name = String()
    age = Integer()

    def __init__(self,myname,myage):
        self.name.value = myname
        self.age.value = myage

Rather than doing self.name.value = name, how can you emulate overloading of the assignment operator so that myname is assigned to self.name.value when you do self.name = myname?

espeed
  • 4,754
  • 2
  • 39
  • 51
  • I ended up creating a metaclass to register the typed attributes (which are all subclasses of the `Property` class). Then I overloaded the `__setattr__` method in the `Example` (`Model`) class to type check those attributes registered by the metaclass. See https://github.com/espeed/bulbs/blob/master/bulbs/model.py – espeed Feb 02 '13 at 06:51
  • Are you using `traits`? – pradyunsg Oct 18 '13 at 18:30
  • No, I rolled my own `Property` class https://github.com/espeed/bulbs/blob/master/bulbs/property.py , which the Model's metaclass uses. See the Bulbs Model API docs http://bulbflow.com/docs/api/bulbs/model/ – espeed Nov 18 '13 at 18:13
  • Check out Enthought's `traits` library. (It has stuff like this, with more support for other stuff). Also, what you need are [descriptors](http://docs.python.org/2/howto/descriptor.html). There is an example there about the same. – pradyunsg Nov 19 '13 at 09:45

4 Answers4

13

In this very special case, in attribute assignment, you can use a descriptor. In fact, I suspect that in the example you are using, Integer and String are actually descriptors.

Aside from using premade descriptors, the easiest way to use descriptors is with property(). here's a brief example:

>>> class Foo(object):
        @property
        def bar(self):
            print 'bar'
            return 'bar'
        @bar.setter
        def bar(self, value):
            print 'bar =', value


>>> afoo = Foo()
>>> afoo.bar
bar
'bar'
>>> afoo.bar = 'baz'
bar = baz
>>> 
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • Yes, that might work. I created a class String() with __get__(), __set__(), and a method to_db(); however, when I do name = String(), I can't do self.name.to_db() because it's calling to_db() on the value returned by __get__(), not the object "name". One way to deal with this is to not call self.name.to_db() directly and instead set a flag in instance and create a conditional in __get__() to check for it and call to_db() if it's True, but this seems kludgy. Is there a better way? – espeed May 16 '11 at 20:28
  • If you want to be able to do `self.attr1.attr2`, you probably don't want a descriptor for `attr1`. For one thing, you generally don't have one descriptor per instance, you have one per class, so you'll have to go to a lot of trouble getting per instance information. Descriptors mostly serve to *hide* implementation details like database persistence. Instead, you should implement the full functionality in terms of the descriptor special method names, and possibly a metaclass on the parent. – SingleNegationElimination May 17 '11 at 01:59
2

You cannot overload the assignment operator in python however with some clever overloading of magic methods you can get to A <<= B+C by overloading the rshift magic method, for a comprehensive guide on pythons magic methods see this.

anijhaw
  • 8,954
  • 7
  • 35
  • 36
0

I ended up creating a Model metaclass called ModelMeta that registers the typed attributes.

See http://github.com/espeed/bulbs/blob/master/bulbs/model.py

In this case, the typed attributes are graph-database "properties", which are all subclasses of the Property class.

See https://github.com/espeed/bulbs/blob/master/bulbs/property.py

Here's an example Model declaration:

# people.py

from bulbs.model import Node, Relationship
from bulbs.property import String, Integer, DateTime
from bulbs.utils import current_datetime

class Person(Node):

    element_type = "person"

    name = String(nullable=False)
    age = Integer()


class Knows(Relationship):

    label = "knows"

    created = DateTime(default=current_datetime, nullable=False)

Example usage:

>>> from people import Person
>>> from bulbs.neo4jserver import Graph
>>> g = Graph()

# Add a "people" proxy to the Graph object for the Person model:
>>> g.add_proxy("people", Person)

# Use it to create a Person node, which also saves it in the database:
>>> james = g.people.create(name="James")
>>> james.eid
3
>>> james.name
'James'

# Get the node (again) from the database by its element ID:
>>> james = g.people.get(james.eid)

# Update the node and save it in the database:
>>> james.age = 34
>>> james.save()

# Lookup people using the Person model's primary index:
>>> nodes = g.people.index.lookup(name="James")

See...

espeed
  • 4,754
  • 2
  • 39
  • 51
0

You can't overload assignment. It's not an operator. You would be better off here just constructing the value in the object constructor.

class Example(object):

    def __init__(self,myname, myage):
        self.name = String(myname)
        self.age = Integer(myage)

However in this case I don't see why you can't just use the built-in str and int.

Keith
  • 42,110
  • 11
  • 57
  • 76