类在很多编程语言中基本上都会涉及,也非常有用。如果你是 Java 或者 Scala 语言的使用者,那么一定很熟悉类的私有方法(通常是以private进行修饰),但是 Python 中如何创建私有方法,这是很多 Python 学习者经常会忽略的地方,本篇文章我们来做一个详细的介绍。

1. 使用场景

相信很多同学和我之前一样,在进行类方法编写的时候,并不会过多关注方法的访问权限,总觉得所有方法都可以被类的实例所访问不是挺好的么,且这种想法在工作种一直伴随我很久。直到我开始自己整理一些日常工具,并进行包的发版,我才发现很多类方法是没有必要呈现给使用者的(因为这些方法单独使用的场景非常少),熟练地使用类私有方法有以下有点:

  • 可以让整个类的设计变得非常清晰,只暴露必要的类方法出来
  • 使用者也倾向于只需要了解必要的函数功能

下面我们来看一个示例,想要实现查询指定学生 ID 的成绩和年龄,但首先需要判断该学生 ID 是否存在:

  1. class Person(object):
  2. def __init__(self, student_id):
  3. self.student_id = student_id
  4. def get_score(self):
  5. is_exists = db.query("SELECT score FROM students WHERE student_id = %s" % self.student_id)
  6. score = db.query("SELECT score FROM score WHERE student_id = %s" % self.student_id) if is_exists else None
  7. return score
  8. def get_age(self):
  9. is_exists = db.query("SELECT score FROM students WHERE student_id = %s" % self.student_id)
  10. age = db.query("SELECT FROM info WHERE student_id = %s" % self.student_id) if is_exists else None
  11. return age

可以看出无论是查询成绩还是年龄,都先需要判断该学生 ID 是否存在,那么我们首先将判断学生 ID 是否存在封装成函数:

  1. class Person(object):
  2. def __init__(self, student_id):
  3. self.student_id = student_id
  4. def is_exists(self):
  5. is_exists = db.query("SELECT score FROM students WHERE student_id = %s" % self.student_id)
  6. return True if is_exists else False
  7. def get_score(self):
  8. score = db.query("SELECT score FROM score WHERE student_id = %s" % self.student_id) if self.is_exists() else None
  9. return score
  10. def get_age(self):
  11. age = db.query("SELECT FROM info WHERE student_id = %s" % self.student_id) if self.is_exists() else None
  12. return age
  13. p = Person(10000)
  14. p.is_exists() # False

但这个有个问题就是,我们在实例化Person类时,所构造的实例是可以直接使用is_exists函数,但是作为使用者来说,其实我们值关注于如何获取成绩和年龄,并不需要判断是否存在这个函数,所以下面我们将其改造成私有方法。

2. 私有方法

在 Python 类当中,如果方法名以双下划线(__)开始,但不以双下划线(__)结尾,这类方法称之为类的私有方法。如果方法名以双下划线开始和结尾的话,我们则称之为类的构造方法

类的私有方法不可以从该类外面进行调用,即使是类的实例也不可以,对私有方法的调用只能存在于该类之内,这一点和类的私有属性基本一致。

  1. class Person(object):
  2. def __init__(self, student_id):
  3. self.student_id = student_id
  4. def __is_exists(self):
  5. is_exists = db.query("SELECT score FROM students WHERE student_id = %s" % self.student_id)
  6. return True if is_exists else False
  7. def get_score(self):
  8. score = db.query("SELECT score FROM score WHERE student_id = %s" % self.student_id) if self.__is_exists() else None
  9. return score
  10. def get_age(self):
  11. age = db.query("SELECT FROM info WHERE student_id = %s" % self.student_id) if self.__is_exists() else None
  12. return age
  13. p = Person(10000)
  14. p.__is_exists() # AttributeError: 'Person' object has no attribute '__is_exists'

再次调用__is_exists方法时,解释器鬼告诉我们Person类没有这个属性,这样使用起来我们只会看到该类有get_scoreget_age2 个方法,整个类就变得非常干净。