Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

2 names for a same attribute

Tags:

python

I would like to know if there is a way to "link" two attributes of a class or to give 2 names to a same attribute?

For example, I'm actually working on a script which create triangle from data given by users. My triangle is ABC. Sides of this triangle are AB, BC and CA. So the triangle has got these 3 attributes (self.AB, self.BC, self.CA). But AB = BA so I would like to allow users to do print myInstance.BA instead of print myInstance.AB.

So I thought to create the attribute self.AB and the property BA (which return self.AB). That work fine when I try to do print myInstance.BA instead of print myInstance.AB but I'm greedy...

I also would like to allow users to do myInstance.BA = 5 instead of myInstance.AB = 5 and when doing this also edit the attribute AB.

Is there is a way to do this ?

like image 462
Morgan Avatar asked Jun 03 '15 21:06

Morgan


2 Answers

Python properties can have setters. So all you need is

class Foo(object):

  @property
  def BA(self):
      return self.AB

  @BA.setter
  def BA(self, value):
      self.AB = value

And insipred by @amccormack's answer, if you can rely on the order of attribute names, this works more generically for e.g. edges bc, cd:

  class Foo(object):


      def __init__(self):
          self.ab = 100

      def __getattr__(self, name):
          return getattr(self, "".join(sorted(name)))

      def __setattr__(self, name, value):
          super(Foo, self).__setattr__("".join(sorted(name)), value)


  f = Foo()

  print f.ba
  f.ba = 200
  print f.ba
like image 177
deets Avatar answered Nov 13 '22 10:11

deets


One way to do this is to store your sides in a custom implementation of a dictionary, as described in this SO answer.

The benefit of this technique, is that you don't have to know what the names of the sides will be when writing the code.

What we did was change the hash lookup function so that before the dictionary looks for a key, it sorts the key. Because the key is sorted, ba becomes ab, etc. The sorting happens in the __keytransform__ function within the SideDict class.

import collections


class TransformedDict(collections.MutableMapping):
    """A dictionary that applies an arbitrary key-altering
       function before accessing the keys"""

    def __init__(self, *args, **kwargs):
        self.store = dict()
        self.update(dict(*args, **kwargs))  # use the free update to set keys

    def __getitem__(self, key):
        return self.store[self.__keytransform__(key)]

    def __setitem__(self, key, value):
        self.store[self.__keytransform__(key)] = value

    def __delitem__(self, key):
        del self.store[self.__keytransform__(key)]

    def __iter__(self):
        return iter(self.store)

    def __len__(self):
        return len(self.store)

    def __keytransform__(self, key):
        return key

class SideDict(TransformedDict):

    def __keytransform__(self, key):
        return ''.join(sorted(key))

side=SideDict()
print 'assign 3 to abc'
side['abc']=3
print "side['abc']", side['abc']
print 'assign 5 to abc'
side['bac']=5
print "side['abc']", side['abc']
print "side['bca']", side['bca']

Running this code produces:

assign 3 to abc
side['abc'] 3
assign 5 to abc
side['abc'] 5
side['bca'] 5
like image 25
amccormack Avatar answered Nov 13 '22 10:11

amccormack