(翻译)30天学习Python👨‍💻第九天——面向对象特性

236 阅读5分钟

30天学习Python👨‍💻第九天——面向对象特性

我在学校里学的第一门编程语言是BlueJ,那是在我五年级的时候。那是一个为初学者设计的Java开发环境,是我们学校的课程。那是我第一次接触面向对象编程。虽然那个时候我不理解,但是我依然记得我们的电脑老师解释面向对象的特性。当我探索Python中面向对象特性时,我回忆了当时我们老师的类比,现在我尝试将它们与我自己的理解结合起来。

面向对象有4个特性,或者说是有4个核心原则:

封装

在上次我介绍面向对象基础时,已经间接的介绍了封装。简单来说,封装就是创建一个容器,将属性和与这些属性相关的操作组合在一起。

class Avenger:
  def __init__(self, name, knownAs):
    self.name = name
    self.knownAs = knownAs

  def reveal_identity(self):
    print(f'I am {self.name}, also known as {self.knownAs}')

hulk = Avenger('Bruce Banner', 'Hulk')
iron_man = Avenger('Tony Stark', 'IronMan')

hulk.reveal_identity() # I am Bruce Banner, also known as Hulk
iron_man.reveal_identity() # I am Tony Stark, also known as IronMan

在上面的类中,当reveal_identity被调用时,每一个Avenger的名字都会被打印出来。换句话说,这些能够执行一些行为的方法让类变得更强大。当从一个类中实例化出来一个对象时,我们只需要调用这些方法执行而不需要知道这些行为是如何运作的,非常的方便。

抽象

学习驾驶汽车时,我们只需要分清楚油门、刹车和离合(假设是一辆自动假设汽车)。作为司机,我们不需要知道汽车是怎么加速的,或者踩刹车时是如何停下的。这就是抽象,现实生活中随处可见,比如轻轻按下电源键就能启动电脑,轻按屏幕就能拍下手机上的照片等等。在上面的例子中,reveal_identity方法就是抽象。

class Avenger:
  def __init__(self, name, knownAs):
    self.name = name
    self.knownAs = knownAs

  def reveal_identity(self):
    print(f'I am {self.name}, also known as {self.knownAs}')

hulk = Avenger('Bruce Banner', 'Hulk')

hulk.name = 'Thanos'
hulk.knownAs = 'Loki'

hulk.reveal_identity() # I am Thanos, also known as Loki

上面类的实现有一个问题,尽管hulk (浩克)被创建了出来,洛基决定把浩克伪装成灭霸!(译者注:意思是说hulk对象被修改了)。这不是我们想要的,所以现在虽然实现了封装和抽象,但内部功能可以从外部被篡改或修改。

默认情况下,Python不支持创建私有变量。我们必须进行更多的探索,看看是否有可能使变量和方法不可访问,实现真正的抽象。

有一个约定是通过在变量前面加上_来创建一个私有变量。这能够让开发者知道这是一个私有变量,不会去尝试更新这些变量和方法(尽管他们可以)。这和在JavaScipt中定义一个私有变量非常像(译者注:指约定俗成的定义)。

继承

继承就像它的名字所暗示的那样,意思是说可以从一个类继承属性和方法。基于一个父类,可以创建任意数量的子类,它们都继承自这个父类。这样做是为了在相似的类中共享函数功能,而不是重复的编写逻辑。

class Player:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  def run(self):
    return f'{self.name} is running'

class Cricketer(Player): # 类继承的语言
  def catch_ball(self):
    return f'{self.name} Caught the ball'

class Batsman(Cricketer):
  def swing_bat(self):
    return f'what a shot by {self.name}'

player1 = Batsman('Virat Kohli', 31)

print(player1.run())
print(player1.catch_ball())
print(player1.swing_bat())

player1Batsman 类的一个实例。Batsman 类是Cricketer类的一个子类。在JavaScript中,类继承使用的是extends关键字。所以在我的认知中,我把二者进行了比较。Cricketer 类是Player 的子类,或者说继承自Player 类。

因为player1Batsman类创建出来的一个对象,所以它有一个swing_bat的方法。它也继承了Player 类的run方法。

在Python中,有一个非常好用的内置函数,isinstance可以用于检测一个对象是不是继承自一个类的。

class Player:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  def run(self):
    return f'{self.name} is running'

class Cricketer(Player):
  def catch_ball(self):
    return f'{self.name} Caught the ball'

class Batsman(Cricketer):
  def swing_bat(self):
    return f'what a shot by {self.name}'

player1 = Batsman('Virat Kohli', 31)

print(isinstance(player1, Batsman)) # True
print(isinstance(player1, Cricketer)) # True
print(isinstance(player1, Player)) # True
print(isinstance(player1, object)) # True

Python中一切皆对象,所有的类都继承了基类对象的所有属性和方法。

多态

Poly的意思是很多形式,所以它的字面意思是以多种形式出现。这个特性可以使对象类共享相同的方法,但是这些方法可以根据调用它们的对象执行不同的操作。

class ProgrammingLanguage:
  def __init__(self, name):
    self.name = name

class JavaScript(ProgrammingLanguage):
  def comment(self):
    return(f'// A Comment in {self.name}')

class Python(ProgrammingLanguage):
  def comment(self):
    return(f'# A comment in {self.name}')

language1 = JavaScript('JavaScript')
language2 = Python('Python')

def add_comment(languageObject):
  print(languageObject.comment())

add_comment(language1) # // A Comment in JavaScript
add_comment(language2) # # A comment in Python

for language in [language1, language2]:
  print(language.comment())
# // A Comment in JavaScript
# # A comment in Python

在上面的代码块中,我创建了一个通用函数add_comment,它接受一个ProgrammingLanguage对象,并调用这个对象的comment()方法。同样的comment方法,当用不同的对象调用时,会根据comment方法的实现产生不同的结果。

第二个场景中,当循环遍历一个ProgrammingLanguage对象列表时,在它们上调用相同的方法时会产生不同的结果。

这就是多态。

虽然没有具体的指导方针或规则来说明何时应该使用什么样的OOP原则,但这取决于具体的问题,解决方案是可以通过多种方式应用OOP概念来实现。

今天就到这里了。我的知识体系正在发生改变,我试图构建脑海中编程概念的网络。

明天我计划介绍完OOP剩下的概念,并做一些有趣的编码练习,然后再进入另一个令人兴奋的编程范式。

原文链接

30 Days of Python 👨‍💻 - Day 9 - OOP Pillars