关于python:为什么在该类的方法中对类的名称进行硬编码被认为是不好的做法?

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

在Python中,为什么这样做是件坏事:

1
2
3
4
5
6
7
8
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)

面积法的定义如下:

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

也就是说,除非我弄错了,否则我认为这是引用类变量的更好方法。问题是为什么?凭直觉,我不喜欢,但我似乎不完全理解这一点。


因为如果您对类进行子类化,它将不再引用该类,而是引用它的父类。在你的情况下,这并没有什么不同,但在许多情况下,它确实有:

1
2
3
4
5
6
7
class Rectangle(object):
    name ="Rectangle"
    def print_name(self):
        print(self.__class__.name) # or print(type(self).name)

class Square(Rectangle):
    name ="Square"

如果实例化Square然后调用它的print_name方法,它将打印"square"。如果使用Rectangle.name而不是self.__class__.name(或type(self).name),它将打印"矩形"。


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

不是。我不知道你为什么这么认为。

有很多很好的理由可以将类的名称硬编码到它的方法中。例如,在python 2上使用super

1
super(ClassName, self).whatever()

人们经常试图用super(self.__class__, self).whatever()来代替它,这样做是完全错误的。第一个参数必须是发生在super调用中的实际类,而不是self.__class__调用中的实际类,否则查找将发现错误的方法。

硬编码类名的另一个原因是避免重写。例如,假设您已经使用另一个方法实现了一个方法,如下所示:

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

如果您希望slightly_different_calculation独立于big_complicated_calculation的覆盖,可以明确地引用Foo.big_complicated_calculation

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

即使你确实想接受覆盖,通常还是把ClassName.whatever改为self.whatever,而不是self.__class__.whatever


我可以说出两个原因

继承

1
2
3
4
5
6
7
class WeirdCircle(Circle):
    pi = 4

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

当您想重命名类时,只有一个点需要修改。


python的zen说尽可能简单地让代码可读。为什么要使用类名或super。如果只使用self,那么它将引用相关类并打印相关变量。请参阅下面的代码。

1
2
3
4
5
6
7
8
9
10
class Rectangle(object):
    self.name ="Rectangle"
    def print_name(self):
        print(self.name)

class Square(Rectangle):
    name = 'square'

sq = Square()
sq.print_name