本文概述
面向对象编程是编写功能强大的应用程序的一种广泛使用的概念。作为数据科学家, 你将需要编写应用程序来处理数据, 以及其他一系列事情。在本教程中, 你将发现Python中面向对象编程的基础。你将学到以下内容:
- 如何建立课程
- 实例化对象
- 向类添加属性
- 在类中定义方法
- 将参数传递给方法
- OOP如何在Python中用于金融
OOP:简介
相对于其他设计模式, 面向对象编程具有一些优势。开发更快, 更便宜, 并且具有更好的软件可维护性。反过来, 这导致了更高质量的软件, 该软件也可以通过新的方法和属性进行扩展。但是, 学习曲线较陡。对于初学者来说, 这个概念可能太复杂了。通过计算, OOP软件速度较慢, 并且由于必须编写更多的代码行而使用更多的内存。
面向对象的编程基于命令式编程范例, 该命令范例使用语句来更改程序的状态。它着重于描述程序应如何运行。命令式编程语言的示例包括C, C ++, Java, Go, Ruby和Python。这与声明式编程相反, 后者只关注计算机程序应完成的工作, 而不指定如何完成。示例是诸如SQL和XQuery之类的数据库查询语言, 其中仅告诉计算机要从何处查询哪些数据, 而现在却告诉他们如何执行。
OOP使用对象和类的概念。可以将类视为对象的”蓝图”。它们可以具有自己的属性(它们具有的特征)和方法(它们执行的动作)。
OOP示例
类的一个示例是Dog类。不要以为它是特定的狗还是自己的狗。总的来说, 我们正在描述狗是什么并且可以做什么。狗通常有名字和年龄。这些是实例属性。狗也可以吠叫;这是一种方法。
当谈论特定的狗时, 在编程中将有一个对象:对象是类的实例。这是面向对象编程所基于的基本原理。例如, 我的狗Ozzy属于Dog类。他的属性是name =’Ozzy’和age =’2’。不同的狗将具有不同的属性。
Python中的OOP
Python是支持OOP的出色编程语言。你将使用它来定义带有属性和方法的类, 然后将其调用。与其他编程语言(如Java, C ++或R)相比, Python具有许多优点。它是一种动态语言, 具有高级数据类型。这意味着开发比使用Java或C ++快得多。它不需要程序员声明变量和参数的类型。这也使Python对于初学者来说更容易理解和学习, 其代码更具可读性和直观性。
如果你是Python的新手, 请务必阅读srcmini的Python for Data Science入门课程。
如何建立课程
要在Python中定义一个类, 可以使用class关键字, 后跟类名和冒号。在类内部, 必须使用def定义__init__方法。这是你以后可以用来实例化对象的初始化程序。它类似于Java中的构造函数。 __init__必须始终存在!它有一个参数:self, 指的是对象本身。在该方法内部, 到目前为止一直使用pass关键字, 因为Python希望你在此处键入内容。切记使用正确的缩进!
class Dog:
def __init__(self):
pass
注意:Python中的self等同于C ++或Java中的self。
在这种情况下, 你有一个(几乎为空)Dog类, 但是还没有对象。让我们创建一个!
实例化对象
要实例化一个对象, 请键入类名, 后跟两个方括号。你可以将其分配给变量以跟踪对象。
ozzy = Dog()
并打印:
print(ozzy)
<__main__.Dog object at 0x111f47278>
向类添加属性
打印ozzy之后, 很明显该对象是狗。但是你尚未添加任何属性。让我们通过重写为Dog类指定名称和年龄:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
你可以看到该函数现在在self后面接受两个参数:name和age。然后将它们分别分配给self.name和self.age。现在, 你可以创建一个具有名称和年龄的新的ozzy对象:
ozzy = Dog("Ozzy", 2)
要在Python中访问对象的属性, 可以使用点表示法。这是通过键入对象的名称, 后跟一个点和属性的名称来完成的。
print(ozzy.name)
print(ozzy.age)
Ozzy
2
这也可以用更详细的句子组合:
print(ozzy.name + " is " + str(ozzy.age) + " year(s) old.")
Ozzy is 2 year(s) old.
这里使用str()函数将age属性(它是整数)转换为字符串, 因此可以在print()函数中使用它。
在类中定义方法
现在你有了aDog类, 它确实具有可以跟踪的名称和年龄, 但实际上并没有执行任何操作。这是实例方法出现的地方。你可以重写该类, 使其现在包含bark()方法。注意如何再次使用def关键字以及self参数。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print("bark bark!")
在实例化一个新的ozzy对象之后, 现在可以使用点表示法调用树皮方法。该方法应打印”树皮”!到屏幕。请注意.bark()中的括号(花括号)。这些总是在调用方法时使用。在这种情况下, 它们为空, 因为bark()方法不接受任何参数。
ozzy = Dog("Ozzy", 2)
ozzy.bark()
bark bark!
回想一下你之前如何打印ozzy?现在, 下面的代码使用doginfo()方法在Dog类中实现此功能。然后, 你实例化具有不同属性的某些对象, 并在它们上调用方法。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print("bark bark!")
def doginfo(self):
print(self.name + " is " + str(self.age) + " year(s) old.")
ozzy = Dog("Ozzy", 2)
skippy = Dog("Skippy", 12)
filou = Dog("Filou", 8)
ozzy.doginfo()
skippy.doginfo()
filou.doginfo()
Ozzy is 2 year(s) old.
Skippy is 12 year(s) old.
Filou is 8 year(s) old.
如你所见, 你可以对带有点标记的对象调用doginfo()方法。现在, 响应取决于你要在哪个Dog对象上调用方法。
由于狗会变老, 所以如果你可以相应地调整它们的年龄会很好。奥兹刚满3岁, 所以我们改变他的年龄。
ozzy.age = 3
print(ozzy.age)
3
就像为属性分配新值一样简单。你还可以在Dog类中将其实现为Birthday()方法:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print("bark bark!")
def doginfo(self):
print(self.name + " is " + str(self.age) + " year(s) old.")
def birthday(self):
self.age +=1
ozzy = Dog("Ozzy", 2)
print(ozzy.age)
2
ozzy.birthday()
print(ozzy.age)
3
现在, 你无需手动更改狗的年龄。每当它是生日时, 你都可以调用Birthday()方法。
将参数传递给方法
你希望我们的狗有一个伙伴。这应该是可选的, 因为并非所有的狗都善于交际。看一下下面的setBuddy()方法。像往常一样, 它以自我为中心, 而伙伴则为自变量。在这种情况下, 伙伴将是另一个Dog对象。将self.buddy属性设置为buddy, 并将buddy.buddy属性设置为self。这意味着这种关系是对等的。你是你的伙伴的伙伴。在这种情况下, Filou将成为Ozzy的好友, 这意味着Ozzy自动成为Filou的好友。你也可以手动设置这些属性, 而不是定义方法, 但是每次你要设置好友时, 这将需要更多的工作(编写2行代码而不是1行)。请注意, 在Python中, 你无需指定参数的类型。如果这是Java, 则将是必需的。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print("bark bark!")
def doginfo(self):
print(self.name + " is " + str(self.age) + " year(s) old.")
def birthday(self):
self.age +=1
def setBuddy(self, buddy):
self.buddy = buddy
buddy.buddy = self
现在, 你可以使用点表示法调用该方法, 并将另一个Dog对象传递给该方法。在这种情况下, Ozzy的好友将是Filou:
ozzy = Dog("Ozzy", 2)
filou = Dog("Filou", 8)
ozzy.setBuddy(filou)
如果现在想获得有关Ozzy好友的一些信息, 则可以使用两次点号:。首先, 引用Ozzy的好友, 第二次引用Ozzy的属性。
print(ozzy.buddy.name)
print(ozzy.buddy.age)
Filou
8
注意如何也可以为Filou完成此操作。
print(filou.buddy.name)
print(filou.buddy.age)
Ozzy
2
也可以调用伙伴的方法。传递给doginfo()的self参数现在是ozzy.buddy, 它是不可靠的。
ozzy.buddy.doginfo()
Filou is 8 year(s) old.
示例:Python中用于财务的OOP
关于Python的面向对象编程可能会派上用场的一个示例是我们的Python金融版:算法交易教程。 Karlijn在其中解释了如何为股票投资组合设置交易策略。交易策略基于股票价格的移动平均线。如果满足信号[‘short_mavg’] [short_window:]>信号[‘long_mavg’] [short_window:], 则创建信号。该信号是对股票未来价格变化的预测。在下面的代码中, 你将看到首先进行初始化, 然后是移动平均值计算和信号生成。由于这不是面向对象的代码, 因此它只是立即执行的一大块。注意, 在示例中我们使用的是aapl, 它是Apple的股票行情自动收录器。如果要对其他库存执行此操作, 则必须重写代码。
# Initialize
short_window = 40
long_window = 100
signals = pd.DataFrame(index=aapl.index)
signals['signal'] = 0.0
# Create short simple moving average over the short window
signals['short_mavg'] = aapl['Close'].rolling(window=short_window, min_periods=1, center=False).mean()
# Create long simple moving average over the long window
signals['long_mavg'] = aapl['Close'].rolling(window=long_window, min_periods=1, center=False).mean()
# Create signals
signals['signal'][short_window:] = np.where(signals['short_mavg'][short_window:] > signals['long_mavg'][short_window:], 1.0, 0.0)
# Generate trading orders
signals['positions'] = signals['signal'].diff()
# Print `signals`
print(signals)
在面向对象的方法中, 你只需编写一次初始化和信号生成代码。然后, 你可以为要在其上计算策略的每只股票创建一个新对象, 并在其上调用generate_signals()方法。注意, 除了自身之外, OOP代码与上面的代码非常相似。
class MovingAverage():
def __init__(self, symbol, bars, short_window, long_window):
self.symbol = symbol
self.bars = bars
self.short_window = short_window
self.long_window = long_window
def generate_signals(self):
signals = pd.DataFrame(index=self.bars.index)
signals['signal'] = 0.0
signals['short_mavg'] = bars['Close'].rolling(window=self.short_window, min_periods=1, center=False).mean()
signals['long_mavg'] = bars['Close'].rolling(window=self.long_window, min_periods=1, center=False).mean()
signals['signal'][self.short_window:] = np.where(signals['short_mavg'][self.short_window:] > signals['long_mavg'][self.short_window:], 1.0, 0.0)
signals['positions'] = signals['signal'].diff()
return signals
现在, 你可以简单地实例化具有所需参数的对象, 并为其生成信号。
apple = MovingAverage('aapl', aapl, 40, 100)
print(apple.generate_signals())
为另一只股票执行此操作变得非常容易。只需实例化具有不同股票代号的新对象即可。
microsoft = MovingAverage('msft', msft, 40, 100)
print(microsoft.generate_signals())
恭喜你!
现在, 你知道如何声明类和方法, 实例化对象, 设置其属性以及调用实例方法。在你作为数据科学家的未来职业中, 这些技能将派上用场。如果你想扩展进一步使用Python所需的关键概念, 请务必查看我们的数据科学中级Python课程。
使用OOP, 随着程序的扩大, 代码的复杂性也会随之增加。你将拥有不同的类, 子类, 对象, 继承, 实例方法等。你需要保持代码的正确结构和可读性。为此, 建议遵循设计模式。这些是代表一组避免不良设计的准则的设计原则。它们各自代表了OOP中经常发生的特定问题, 并描述了该问题的解决方案, 然后可以重复使用。这些OOP设计模式可以分为几类:创建模式, 结构模式和行为模式。创建模式的一个示例是单例, 当你要确保只能创建一个类的实例时, 应使用单例。迭代器(用于循环访问集合中的所有对象)是行为模式的一个示例。 oodesign.com是设计模式的绝佳资源。如果你更喜欢书籍, 我建议你阅读”设计模式:可重用的面向对象软件的元素”。
评论前必须登录!
注册