4

In python, why is it a bad thing to do something like this:

class Circle:
  pi = 3.14159 # class variable
  def __init__(self, r = 1):
    self.radius = r
  def area(self):
    return Circle.pi * squared(self.radius)

def squared(base): return pow(base, 2)

The area method could be defined as follows:

def area(self): return self.__class__.pi * squared(self.radius) 

which is, unless I'm very much mistaken, considered a better way to reference a class variable. The question is why? Intuitively, I don't like it but I don't seem to completely understand this.

weeCoder
  • 272
  • 2
  • 10

4 Answers4

4

Because in case you subclass the class it will no longer refer to the class, but its parent. In your case it really doesn't make a difference, but in many cases it does:

class Rectangle(object):
    name = "Rectangle"
    def print_name(self):
        print(self.__class__.name) # or print(type(self).name)

class Square(Rectangle):
    name = "Square"

If you instantiate Square and then call its print_name method, it'll print "Square". If you'd use Rectangle.name instead of self.__class__.name (or type(self).name), it'd print "Rectangle".

sarnthil
  • 395
  • 2
  • 7
  • It should also be noted that as long as you keep a clear distinction between instance attributes and class attributes, you don't even _need_ to get a reference to the class. `self.name` will resolve to the same thing that `type(self).name` resolves to as long as you haven't set a `name` on `self`. – mgilson Sep 08 '16 at 20:24
  • This is assuming you want the thing to be overrideable, and if you want it to be overrideable, it's probably better to use `self.whatever` instead of `self.__class__.whatever`. Not everything should actually be overrideable. – user2357112 Sep 08 '16 at 20:25
2

I can name here two reasons

Inheritance

class WeirdCircle(Circle):
    pi = 4

c = WeirdCircle()
print(c.area()) 
# returning 4 with self.__class__.pi 
# and 3.14159 with Circle.pi

When you want to rename the class, there is only one spot to modify.

phi
  • 10,572
  • 3
  • 21
  • 30
2

Why is it considered bad practice to hardcode the name of a class inside that class's methods?

It's not. I don't know why you think it is.

There are plenty of good reasons to hardcode the name of a class inside its methods. For example, using super on Python 2:

super(ClassName, self).whatever()

People often try to replace this with super(self.__class__, self).whatever(), and they are dead wrong to do so. The first argument must be the actual class the super call occurs in, not self.__class__, or the lookup will find the wrong method.

Another reason to hardcode the class name is to avoid overrides. For example, say you've implemented one method using another, as follows:

class Foo(object):
    def big_complicated_calculation(self):
        return # some horrible mess
    def slightly_different_calculation(self):
        return self.big_complicated_calculation() + 2

If you want slightly_different_calculation to be independent of overrides of big_complicated_calculation, you can explicitly refer to Foo.big_complicated_calculation:

def slightly_different_calculation(self):
    return Foo.big_complicated_calculation(self) + 2

Even when you do want to pick up overrides, it's usually better to change ClassName.whatever to self.whatever instead of self.__class__.whatever.

user2357112
  • 260,549
  • 28
  • 431
  • 505
0

Zen of python says keep your code as simple as possible to make it readable. Why to get into using the class name or super. If you just use self then it will refer the relevant class and print its relevant variable. Refer below code.

class Rectangle(object):
    self.name = "Rectangle"
    def print_name(self):
        print(self.name)

class Square(Rectangle):
    name = 'square'

sq = Square()
sq.print_name
Versatile
  • 459
  • 5
  • 20