从脚本编写到面向对象的Python编程

Python 在近年来的受欢迎程度剧增,部分原因在于该语言非常灵活,同时功能非常强大。Python 可用于系统管理、Web 开发、GUI 编程、科学计算等等。本文的主要目标是向习惯于使用 Bash、PHP 或其它某种语言编写脚本过程代码的人介绍面向对象的 Python 开发,并帮助他们转换到面向对象的 Python 开发。Python 的这种日益流行性意味着,对于目前使用其他编程语言的开发人员,除了使用他们最喜欢的语言之外,他们还可以采用 Python 来完成某些项目。

过程式编程当然有其用武之地,并且可能是解决某个问题的高度有效的方法。在非常基本的层次上,过程式编程可定义为指令的列表,Bash 和 PHP 通常就是以这样的方式编写的。然而由于 Python 的流行,对于作为 Web 开发人员或系统管理员的 PHP 和 Bash 脚本编写人员,他们正陷入必须同时学习面向对象的编程和 Python 的境地。

面向对象这个概念很难一次性地掌握,因此本文采用过程式 Bash 和 PHP 脚本,并首先将它们转换为过程式 Python。作为最后一步,它们将转换为面向对象的 Python 这个终结目标。本文在结束时将简略讨论一下面向对象的 Python 的一些优点,然后在最后讨论一些可能更适合采用过程或函数式编程的一些不利场景。到本文结束时,Bash 或 PHP 程序员应该能够毫无畏惧地一头扎进面向对象的 Python 项目。

采用 PHP 和 Bash 编写磁盘监视函数

虽然 PHP 主要是为了在浏览器中运行,但是也可以通过 exec 函数执行系统调用。采用 PHP 编写的第一个示例将捕获 Shell 命令“df –h”的输出,将输出放在一个数组中,然后根据一个正则表达式检查输出的每一行。如果该行与正则表达式匹配,则打印该行。如果您希望从主目录运行此示例,只需将此脚本命名为 index.php,并将其放在 Apache/mod_php 服务器的对外服务目录中。

PHP 磁盘监视示例


//Analyzes disk usage

//Takes regex pattern and message

function disk_space( $pattern="/2[0-9]%/", $message="CAPACITY WARNING:" )

{

exec(escapeshellcmd("df -h"),$output_lines,$return_value);

foreach ($output_lines as $output) {

if (preg_match( $pattern, $output ))

echo "$message $output

";

}

}

disk_space()

?>

复制代码

如果您在浏览器中运行此网页,将会获得以下结果:

CAPACITY WARNING: /dev/sda1 3.8G 694M 2.9G 20% /

查看该代码,可以看到正则表达式模式被设置为匹配某个包含 20-29% 的行。可以容易地修改此模式以适应其他标志,例如 90-99%,因为 20% 是非常低的磁盘容量。

下面让我们看一下如何在 Bash 函数中完成同样的事情。在 Bash 中,该问题要容易解决得多,因为您实际上是在处理系统调用。在此示例中,您甚至不需要使用数组或正则表达式库,因为使用到 grep 的管道容易多了。不过,在 Bash 中设置函数的缺省参数始终有点麻烦。

Bash 磁盘监视示例

#!/usr/bin/env bash

#function flags disk usage takes pattern and message optionally

function disk_space ()

{

#checks for pattern parameter

if [ "$1" != "" ]; then

pattern=$1

else

pattern="2[0-9]%"

fi

#checks for message parameter

if [ "$2" != "" ]; then

message=$2

else

message="CAPACITY WARNING:"

fi

#looks at output for pattern to flag

output_lines=`df -h | grep $pattern`

if [ "$output_lines" != "" ]; then

echo $message $output_lines

fi

}

#example of optional parameters usage

#disk_space 9[0-9]% ALERT:

disk_space

复制代码

当您运行此脚本时,将会获得同样的输出,因此可以跳过输出的显示。您能够从该脚本的 PHP 版本和 Bash 版本中找到的相关性在于,此过程式代码事实上像一组指令一样运行。似乎计算机就像是一个小孩,而您告诉该小孩如何做某件事情,例如第一次系鞋带。在您开始在 Python 中考虑“面向对象范式”之前,让我们首先看一下如何采用 Python 来创建这同一个脚本的过程式版本。

Python 磁盘监视示例

from subprocess import Popen, PIPE

import re

def disk_space(pattern="2[0-9]%", message="CAPACITY WARNING:"):

#takes shell command output

ps = Popen("df -h", shell=True,stdout=PIPE, stderr=PIPE)

output_lines = ps.stdout.readlines()

for line in output_lines():

line = line.strip()

if re.search(pattern,line):

print "%s %s" % (message,line)

disk_space()

复制代码

浏览一下我们的代码的过程式 Python 版本,发现它与 Bash 和 PHP 版本非常相似。对于 Python,子过程模块处理对 Shell 命令的系统调用,并将输出发在一个列表(在 Bash 和 PHP 中称为数组)中。与 PHP 版本非常相似,然后我对命令的标准输出行列表中的项进行了迭代遍历。我寻找构成所寻找模式的正则表达式,然后使用注入的特殊消息来打印该磁盘报告行。这是如何解决自顶向下的脚本问题的经典示例,但是在下一个部分中,您将完全改变这种方法,并从对象的角度考虑问题。

从过程到面向对象的 Python

过程式编程通常是初学的开发人员的最自然编程风格,并且对于许多问题来说也是高度有效的。另一方面,对于创建抽象从而创建可重用的代码来说,面向对象的编程可能是非常有用的方法。然而,当项目达到某种程度的复杂性之后,过程代码通常会暴露出其根本缺陷。下面让我们直接进入上一个示例的面向对象版本,并看看这样有何变化。

面向对象的 Python 磁盘监视脚本

#!/usr/bin/env python

from subprocess import Popen, PIPE

import re

class DiskMonitor():

"""Disk Monitoring Class"""

def __init__(self,

pattern="2[0-9]%",

message="CAPACITY WARNING",

cmd = "df -h"):

self.pattern = pattern

self.message = message

self.cmd = cmd

def disk_space(self):

"""Disk space capacity flag method"""

ps = Popen(self.cmd, shell=True,stdout=PIPE,stderr=PIPE)

output_lines = ps.stdout.readlines()

for line in output_lines:

line = line.strip()

if re.search(self.pattern,line):

print "%s %s" % (self.message,line)

if __name__ == "__main__":

d = DiskMonitor()

d.disk_space()

复制代码

查看该代码的面向对象版本,可以看到代码变得更加抽象。有时,太多的抽象会导致设计问题,但是在此例中,它允许您将问题分离为更多可重用的部分。 DiskMonitor 类具有 __init__ method,您可以在其中定义新的参数,并且 disk_space 函数现在是该类中的一个方法。

使用这种新的样式,您无需更改原始代码即可容易地重用和自定义各个部分,而使用过程代码时则通常必须更改原始代码。面向对象的设计的一个更加功能强大、通常也被过度使用的方面是继承。继承允许您在新的类中重用和自定义现有的代码。让我们在下一个示例中看看继承可能像什么样子。

使用继承的面向对象 Python 磁盘监视脚本

#!/usr/bin/env python

from subprocess import Popen, PIPE

import re

class DiskMonitor():

"""Disk Monitoring Class"""

def __init__(self,

pattern="2[0-9]%",

message="CAPACITY WARNING",

cmd = "df -h"):

self.pattern = pattern

self.message = message

self.cmd = cmd

def disk_space(self):

"""Disk space capacity flag method"""

ps = Popen(self.cmd, shell=True,stdout=PIPE,stderr=PIPE)

output_lines = ps.stdout.readlines()

for line in output_lines:

line = line.strip()

if re.search(self.pattern,line):

print "%s %s" % (self.message,line)

class MyDiskMonitor(DiskMonitor):

"""Customized Disk Monitoring Class"""

def disk_space(self):

ps = Popen(self.cmd, shell=True,stdout=PIPE,stderr=PIPE)

print "RAW DISK REPORT:"

print ps.stdout.read()

if __name__ == "__main__":

d = MyDiskMonitor()

d.disk_space()

复制代码

如果运行这个使用继承的脚本版本,您将获得以下输出:

RAW DISK REPORT:

Filesystem            Size  Used Avail Use% Mounted on

/dev/sda1             3.8G  694M  2.9G  20% /

varrun                252M   48K  252M   1% /var/run

varlock               252M     0  252M   0% /var/lock

udev                  252M   52K  252M   1% /dev

devshm                252M     0  252M   0% /dev/shm

此输出与前面带标记的版本区别非常大,因为它只是使用顶部注入的 print 语句来打印的未经筛选的 df –h 命令结果。通过重写 MyDiskMonitor 类中的方法,您能够完全改变 disk_space 方法的意图。

允许您重用其他类中的属性的 Python 魔法是这个“MyDiskMonitor(DiskMonitor)”语句。您只需在定义新类的名称时,将先前的类的名称放在括号内。一旦完成此步骤,您立即可以访问其他类属性来做自己希望的事情。但是乐趣不仅于此。通过添加另一个通过电子邮件来发送标记消息的方法,也许是将其命名为 disk_alert(self),这样就可以进一步自定义新类。这是面向对象的设计的美妙之处;它允许有经验的开发人员不断重用已编写的代码,从而节省大量的时间。

遗憾的是,面向对象的编程也有其不利的一面。所有这些抽象都是以复杂性为代价的,如果抽象过度,可能会彻底地弄巧成拙。由于 Python 支持多重继承,抽象可以达到相当有害的复杂程度。您是否能够想象只是为了编写一个方法也要查看多个文件的情况?无论相信与否,这种情况的确会发生,并且代表了面向对象编程的不幸现实。

面向对象的编程的替代方案是函数式编程,并且 Python 提供了用于进行函数式以及面向对象和过程式编程的资源。在最后一个示例中,我们将研究如何以函数式的方式编写现已变得非常无聊的磁盘监视代码。

函数式的 Python 磁盘监视脚本

from subprocess import Popen, PIPE

import re

def disk_space(pattern="2[0-9]%", message="CAPACITY WARNING:"):

#Generator Pipeline To Search For Critical Items

ps = Popen("df -h", shell=True,stdout=PIPE, stderr=PIPE)

outline = (line.split() for line in ps.stdout)

flag = (" ".join(row) for row in outline if re.search(pattern, row[-2]))

for line in flag:

print "%s %s" % (message,line)

disk_space()

复制代码

查看这最后一个示例,它与您从本文中看到的所有其他代码的区别都非常大。如果您逐行浏览该代码,可以首先从 “ps”变量中以前未见过的内容开始。接下来的两行代码使用生成器表达式来处理文件对象 ps.stdout,分析该文件并在其中搜索您正在查找的行。如果您将这些代码行剪切并粘贴到交互式的 Python Shell 中,如果打印的话,您将看到概要和标志都是生成器对象。生成器对象附带有下一个方法,因而允许您通过“管道”将操作连在一起。

概要行从一行中去除新行字符,并往下将该行传递给下一个生成器表达式,后者一次一个地在每行中搜索某个正则表达式匹配项,然后将输出传递给标记。此类紧凑的工作流可以替代面向对象的编程样式,并且相当有趣。然而,这种样式也有缺点,因为代码的简洁性会导致难于调试的错误,除非独立地执行每一行代码。函数式编程还很伤脑筋,因为它让您通过将解决方案链接在一起来考虑解决问题。无论是从过程式还是从面向对象样式的角度看,这都是相当不同的。

总结

本文有点试验性质,因为它从 Bash 和 PHP 谈到了过程、面向对象,并在最后谈到了使用相同基本代码的函数式 Python。但愿本文说明了 Python 是一种非常灵活和功能强大的语言,其他编程语言的开发人员也可以学习欣赏。随着 Python 的越来越流行,其他开发人员除了首选语言之外,学习 Python 也将变得更加重要。

Python 最近的两个最大的发展领域是 Web 开发和系统管理。就 Web 开发而言,PHP 开发人员可能很快就必须做出每周的选择,即哪个项目采用 Python 更有意义,以及哪个项目采用 PHP 更有意义。对于系统管理员、Bash 和 Perl 脚本程序员,他们经常被要求采用 Python 完成某些项目。部分是因为这是没有选择的,部分是因为许多供应商正在为他们的产品提供 Python API。在您的工具箱中准备一点 Python 决不会伤害任何人。学好python你需要一个良好的环境,一个优质的开发交流群,群里都是那种相互帮助的人才是可以的,我有建立一个python学习交流群,在群里我们相互帮助,相互关心,相互分享内容,这样出问题帮助你的人就比较多,群号是301,还有056,最后是051,这样就可以找到大神聚合的群,如果你只愿意别人帮助你,不愿意分享或者帮助别人,那就请不要加了,你把你会的告诉别人这是一种分享。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,672评论 18 139
  • 1.创建文件夹 !/bin/sh mkdir -m 777 "%%1" 2.创建文件 !/bin/sh touch...
    BigJeffWang阅读 10,072评论 3 53
  • 背景: 阅读新闻 12C CDB模式下RMAN备份与恢复 [日期:2016-11-29] 来源:Linux社区 作...
    阳屯okyepd阅读 3,441评论 0 7
  • 阳台的花盆,还空着一个。 怪可惜的,思量着养点植物放在里面。娇嫩的花卉养不起,也养不活,见着小区的荒地上,长着不少...
    周世恩阅读 2,170评论 1 10
  • 你是不是很想遇见一位高人可以教你写作呢? 1. 写作就是一次与高人的走心交流。 为什么不说阅读是一次高人交流呢? ...
    烨然v阅读 936评论 6 20