2

I very much like the Don't Repeat Yourself (DRY) principle, and as one instance of it, I don't like to use a class's name within its definition. (If I wanted to change the class name, I would also have to change all of its occurrences within the class definition, where I might forget one.)

Now the typical idiom to accessing superclass attributes I read in the docs contains the class name, like in

class A(object):
    def method(self):
        print('Hi!')
class B(A):
    def method(self):
        super(B, self).method()  # fixed reference to B, not DRY

Using "type(self)" or "self.__class__" instead will lead to infinite recursion when subclassing B.

Do I have to skip DRY in this case? Or is there some other magic attribute which - inside the definition of the subclass - refers to that subclass?

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
virtualnobi
  • 1,140
  • 2
  • 11
  • 35

2 Answers2

1

The example in the documentation uses the explicit name of the child class. As far as I can tell, this is just an unfortunate and unavoidable deficiency of Python 2.7.

However, this seems to work for me:

class A(object):
    def method(self):
        print('Class A method')
class B(A):
    def __init__(self):
        self.myclass = B
        super(self.myclass, self).__init__()
    def method(self):
        print('Class B method')
        super(self.myclass, self).method()

This leaves one occurrence of the explicit class name inside B, but I can avoid any others by using self.myclass.

Tom Barron
  • 1,554
  • 18
  • 23
  • Thanks for the doc reference, Tom. But although this may reduce the number of "B" inside the class definition of "B", it's still not DRY. Since no other answer came up until now, I'll take it as unavoidable, as you write. – virtualnobi Nov 01 '16 at 14:21
0

I know this is an old question, but I wanted to leave this here for reference.

It is possible to automatically add an attribute containing the class with metaclasses.

Something like this will work:

class Metaclass(type):
  def __init__(cls, name, bases, attrs):
    cls.what_class = cls

class A(metaclass=Metaclass):
  pass

class B(A):
  pass

print(A().what_class) # <class 'A'>
print(B().what_class) # <class 'B'>

If you want to use this with another metaclass I would look into this question.

internet_user
  • 3,149
  • 1
  • 20
  • 29