如何写一手漂亮的模型:面向对象编程的设计原则综述
作者:媒体转发 时间:2018-05-12 09:30
面向对象的编程在实现想法乃至系统的过程中都非常重要,我们不论是使用 TensorFlow 还是 PyTorch 来构建模型都或多或少需要使用类和方法。而采用类的方法来构建模型会令代码非常具有可读性和条理性,本文介绍了算法实现中使用类和方法来构建模型所需要注意的设计原则,它们可以让我们的机器学习代码更加美丽迷人。

大多数现代编程语言都支持并且鼓励面向对象编程(OOP)。即使我们最近似乎看到了一些偏离,因为人们开始使用不太受 OOP 影响的编程语言(例如 Go, Rust, Elixir, Elm, Scala),但是大多数还是具有面向对象的属性。我们在这里概括出的设计原则也适用于非 OOP 编程语言。
为了成功地写出清晰的、高质量的、可维护并且可扩展的代码,我们需要以 Python 为例了解在过去数十年里被证明是有效的设计原则。
一、对象类型
因为我们要围绕对象来建立代码,所以区分它们的不同责任和变化是有用的。一般来说,面向对象的编程有三种类型的对象。
1. 实体对象
这类对象通常对应着问题空间中的一些现实实体。比如我们要建立一个角色扮演游戏(RPG),那么简单的 Hero 类就是一个实体对象。
class Hero:
def __init__(self, health, mana):
self._health = health
self._mana = mana
def attack(self) -> int:
"""
Returns the attack damage of the Hero
"""
return 1
def take_damage(self, damage: int):
self._health -= damage
def is_alive(self):
return self._health > 0
这类对象通常包含关于它们自身的属性(例如 health 或 mana),这些属性根据具体的规则都是可修改的。
2. 控制对象(Control Object)
控制对象(有时候也称作管理对象)主要负责与其它对象的协调,这是一些管理并调用其它对象的对象。我们上面的 RPG 案例中有一个很棒的例子,Fight 类控制两个英雄,并让它们对战。
class Fight:
class FightOver(Exception):
def __init__(self, winner, *args, **kwargs):
self.winner = winner
super(*args, **kwargs)
def __init__(self, hero_a: Hero, hero_b: Hero):
self._hero_a = hero_a
self._hero_b = hero_b
self.fight_ongoing = True
self.winner = None
def fight(self):
while self.fight_ongoing:
self._run_round()
print(f'The fight has ended! Winner is #{self.winner}')
def _run_round(self):
try:
self._run_attack(self._hero_a, self._hero_b)
self._run_attack(self._hero_b, self._hero_a)
except self.FightOver as e:
self._finish_round(e.winner)
def _run_attack(self, attacker: Hero, victim: Hero):
damage = attacker.attack()
victim.take_damage(damage)
if not victim.is_alive():
raise self.FightOver(winner=attacker)
def _finish_round(self, winner: Hero):
self.winner = winner
self.fight_ongoing = False



