【问题标题】:Why is it considered bad practice to hardcode the name of a class inside that class's methods?为什么在类的方法中硬编码类的名称被认为是不好的做法?
【发布时间】:2016-09-08 20:08:46
【问题描述】:

在python中,为什么做这样的事情是一件坏事:

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)

面积法可以定义如下:

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

这被认为是引用类变量的更好方法,除非我非常错误。问题是为什么?直觉上,我不喜欢它,但我似乎并没有完全理解这一点。

【问题讨论】:

  • 区域def area(self)中没有self:
  • 你误会了什么,你应该使用Cirlce.pi,而不是self.__class__.pitype(self).pi
  • @Versatile 好像我打错了,一定有 self 在区域内。
  • @BiRico 为什么我不应该使用 self.__class__.pi?

标签: python oop


【解决方案1】:

因为如果您将类子类化,它将不再引用该类,而是它的父类。在您的情况下,它确实没有什么区别,但在许多情况下它确实有:

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),它会打印“矩形”。

【讨论】:

  • 还需要注意的是,只要明确区分实例属性和类属性,甚至不需要获取类的引用。只要您没有在 self 上设置 nameself.name 将解析为与 type(self).name 解析相同的内容。
  • 这是假设你希望这个东西是可覆盖的,如果你希望它是可覆盖的,最好使用self.whatever而不是self.__class__.whatever。并非所有内容实际上都应该是可覆盖的。
【解决方案2】:

为什么在类的方法中硬编码类名被认为是不好的做法?

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

有很多充分的理由在其方法中硬编码一个类的名称。例如,在 Python 2 上使用 super

super(ClassName, self).whatever()

人们经常尝试将其替换为 super(self.__class__, self).whatever(),而他们这样做大错特错。第一个参数必须是发生super调用的实际类,而不是self.__class__,否则查找会找到错误的方法。

对类名进行硬编码的另一个原因是避免覆盖。例如,假设您使用另一种方法实现了一种方法,如下所示:

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

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

即使您确实想要选择覆盖,通常最好将ClassName.whatever 更改为self.whatever 而不是self.__class__.whatever

【讨论】:

    【解决方案3】:

    我可以在这里说出两个原因

    继承

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

    当你想重命名类时,只有一个地方可以修改。

    【讨论】:

      【解决方案4】:

      Zen of python 说让你的代码尽可能简单以使其可读。为什么要使用类名或超级名。如果您只使用 self 那么它将引用相关类并打印其相关变量。参考下面的代码。

      class Rectangle(object):
          self.name = "Rectangle"
          def print_name(self):
              print(self.name)
      
      class Square(Rectangle):
          name = 'square'
      
      sq = Square()
      sq.print_name
      

      【讨论】:

        猜你喜欢
        • 2015-12-12
        • 2010-10-22
        • 2011-11-20
        • 1970-01-01
        • 1970-01-01
        • 2010-11-04
        相关资源
        最近更新 更多