1

Here is a quick example:

class KEY(object):
    A = 'a'
    A = 'b'
    B = 'b'

Is there a way to test that 'A' has been repeatedly defined in class 'KEY' regardless of the assigned value?

Binarycrayon
  • 1,035
  • 6
  • 8
  • This might not be exactly what you need, but most IDE's / code analyzers will point that out. – Thomas Orozco Dec 14 '12 at 17:17
  • @Thomas Orozco Thanks for your suggestion, but I need runtime checks in the unit test suite. – Binarycrayon Dec 14 '12 at 17:20
  • Then *maybe* using a metaclass could do the trick, but I think it wouldn't. *Edit*: Actually, it won't. The variables have already been converted to a dictionary (and hence, duplicates have been removed) when they reach your metaclass code. – Thomas Orozco Dec 14 '12 at 17:25
  • Would overriding `__new__` work? or that happens even beforehand? Sorry I am not quite familier with python 'class loading' process under the hood, and I don't feel I should work on `__import__`. – Binarycrayon Dec 14 '12 at 17:29
  • @ThomasOrozco: actually, Python 3 does have a provision for taht use case. One can have a `__prepare__` method which could make the class parsing use am ordered dict, or some other specialized mapping. – jsbueno Dec 14 '12 at 21:37

2 Answers2

2

Here's an attempt at answer:

Class variables are not going to work

You can't control redefinition for these. Basically, the metaclass is what is called to create your class, and it's passed a dict of attribute => value. We could say it's "already too late".

Using instance variables

You can control what happens when you do a.b = c after class instantiation, so what you could do is:

class RedefinitionMixin(object):
    def __setattr__(self, k, v):
        if hasattr(self, k):
            raise Exception('Attribute redefinition!')
        super(RedefinitionMixin, self).__setattr__(k, v)

class KEY(RedefinitionMixin, object):
    def __init__(self):
        self.A = 'a'
        self.A = 'b'
        self.B = 'b'

This may cause some unexpected behavior if you're already overriding __setattr__ though!

Note that this is only going to work in case you actually instantiate the class.
To circumvent the issue of using an instance, you could implement a singleton pattern.


Overall, I wouldn't recommend that solution, but that's the best I can come up with now.

Thomas Orozco
  • 53,284
  • 11
  • 113
  • 116
  • +1 for giving the reason "Class variables are not going to work", another way is through static analysis by using inspect.getSource to the class and check appearance of each variable name in the class, though you could argue that is no difference compare to pylint. – Binarycrayon Dec 14 '12 at 20:35
  • Just tried it, actualy pylint thinks that redefined class variable is a valid case. – Binarycrayon Dec 14 '12 at 20:50
2

If you're using Python 3, it's possible to do this cleanly using a dict subclass that only allows nonexisting keys to be set and the __prepare__ method of a metaclass. More info here. In Python 2 it's harder; I wrote a horrible hack to achieve it, with some limits.

Community
  • 1
  • 1
kindall
  • 178,883
  • 35
  • 278
  • 309