7

震惊!当Python遇到Excel后,将开启你的认知虫洞

 3 years ago
source link: https://www.cnblogs.com/nokiaguy/p/13043865.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

震惊!当Python遇到Excel后,将开启你的认知虫洞

本文主要内容:
1. Excel,你为什么如此强大
2. 软件开发也需要团队作战
3. Excel的集成方案演化
4. macOS特有的集成方案:applescript
5. Python与Excel集成,有哪些好处
6. 了解多个技术领域,可以间接提高自己的IQ
7. 提高开发效率的利器:生态渗透
8. 上代码:Python到底如何与Excel交互
9. 用Python替代VBA
本文主要讲Python与Excel的关系以及集成方案,Office家族的其他成员,如Word、PowerPoint与Excel拥有类似的功能,Python同样可以与Word、PowerPoint等Office成员结合,这些内容我以后会写文章讲解。
我相信看这篇文章的大多数人都是程序员。在广大程序员的眼里,Excel以及Office家族的其他成员完全不能与Python、Java、Sprint Boot这些技术相比。Office被贴上的标签就是:非专业人员的工具。是由那些体制内的人、会计、业务人员使用的工具,其实这是对Excel的最大误解。
32818-20200604151342571-163801880.png

 1. Excel,你为什么如此强大

Excel从一问世开始,定位就是横跨办公和开发两界。在上个世界末推出的Excel5.0(那时还没有office这个产品套件)就已经支持VBA了,那可是在Win32下(一种基于dos的shell,并不属于真正的操作系统)。尽管有些原始(以现在的眼光看),但在当时却显得极为先进。因为Excel(以及同期的Word)是人类史上第一个内置领域特定语言(DSL)的民用系统(可以被各个领域的人使用的系统)。正是因为有了VBA,Excel才显得非常强大。
可能有的程序员会问,即使Excel支持VBA,可以进行编程,也只不过是完成一些自动化操作而已。VBA的功能完全不能与Python、Java、C#、C++这些被广大程序员熟知的编程语言相比,更别说成为编程领域的主流了。没错,如果单凭VBA本身的确无法与这些流行的编程语言相比,但要知道,VBA和Excel本身可以与其他开发工具融合,也就是说,可以让VBA和Excel成为自己系统的一部分,这就显得非常牛逼了。
32818-20200604151418962-787317015.png

 2. 软件开发也需要团队作战

那么为什么要将Excel与其他系统结合呢?其实在我们创业时、在公司完成一个项目时,甚至在参加篮球比赛时,都会高频率提到一个词:团队。 现在也流行着一句话:没有完美的个人,只有完美的团队。也就是说,没有人可以什么都会,什么都擅长,就算是天才达芬奇也是如此。但团队就不一样了,即使某项工作团队里没人能做,也可以扩充团队成员,吸引能做这项工作的人加入团队。
其实在开发软件的过程中也同样是讲究团队作战的。不管我们使用的开发工具有多强大,用户社区由多庞大,都无法规避一个事实:任何技术都不可能适合完成所有的工作。 当然,还有另外一种说法就是尽管某种技术可以完成某项工作,但并不是最好的选择。
现在回到Excel上来。首先要知道Excel擅长什么,对,没错,Excel擅长表格和图表的制作。尽管有非常多的开发工具也可以制作表格和图表,但很显然,Excel是其中最好的(主要用门槛、易用性、功能和用户基数的综合指标来衡量)。所以,如果某一个系统要求将数据转换为表格和图表,那么这项任务交给Excel来完成是再合适不过了。
3. Excel的集成方案演化
在不同的时期,Excel的集成方案也不尽相同。在Excel的大眼夹时代(那时还是Office97和Office2000的时代),微软与开源世界还水火不容,我也还处于学生时代。在那个时代,Excel只能与Windows下的开发工具融合,其中主要的开发工具包括微软的VC、VB、以及Borland(现在已经消失)的Delphi、C++ Builder等。
 
32818-20200604151505366-793683396.png
最初的集成方案有如下3种:
  • 可视方式:通过OLE组件将Excel直接嵌入窗口中,其实就相当于拥有了一个高级版的表格编辑器
  • VBA方式:通过ActiveX技术创建Excel.Applicaiton对象(一般是CreateObject函数),然后就可以任意调用VBA的API了,我比较喜欢这种方式。通过这种方式,可以将系统中的数据按着一定的格式直接传输到Excel中,给用户提交的是包含表格数据的Excel文档。
  • 反客为主方式:这种方式将Excel作为主体。也就是说,主要的操作界面是Excel,在Excel中调用或访问其他系统。例如,很多年前我做过一个基于Excel的报表系统。该系统分别使用Delphi和Excel实现。Delphi做的管理系统,将数据发送给Excel。但需要用户自己调整报表格式。我采用的方案是通过Excel的VBA实现表格的格式设置。其中有部分功能需要访问SQL Server数据库,以及完成与Delphi实现的系统类似的功能,这部分功能使用了Delphi封装的Dll(COM组件),然后通过Excel反过来调用这些DLL。最终用户使用的方式是用主系统完成大部分工作。如果想调整Excel的报表样式,可以直接用Excel来完成(会在Excel上提供一些自定义的菜单和按钮,现在通过加载项【Add-ins】实现)
32818-20200604151525518-99253011.png
不过随着时间的推移,现在的微软已经拥抱开源和其他系统。所以Excel也不仅限于Windows。在macOS上也可以完成在Windows上的大多数工作,甚至Visual Studio也推出了macOS版本。而且.net core也可以同时跨Windows、macOS和Linux三个平台,SQL Server也开始支持Linux。以后我们会在更多的场景看到微软的身影。
既然Excel已经支持了macOS平台,就需要采用跨平台的方式与Excel集成。当然,前面介绍的几种方案现在仍然可用,但仅限于Windows平台。不过我们无法预测用户到底使用哪一个平台,所以应该尽量使用跨平台方案。
目前主要的跨平台方案有如下3种:
  • 直接修改xlsx文件
  • 通过VBA间接调用其他编程语言
  • 使用office.js
第1中方式有很多编程语言都支持,例如,Python、Java、Julia、Go、JavaScript。几乎你能想到的编程语言,都有支持xlsx格式的库。这里只讨论Python。如果想了解更多关于集成Excel的技术,可以关注我的公众号:极客起源。
在Python语言中,支持Excel文件格式的库非常多,如非常著名的openpyxl、xlsxwriter等。通过这些库,可以在不依赖Excel环境的情况下,生成xlsx格式的文件。不过这些库基本是只是生成Excel文件,并不能更好地利用VBA以及更高级的功能。由于Excel文件格式非常复杂,完全支持比较困难,所以这些库只是支持一部分Excel的功能,但这些功能对于绝大多数需求已经足够了。
第2种其实是一种取巧的方式,通过VBA做桥,调用其他编程语言,相当于用其他编程语言代替了VBA。这其中典型的就是xlwings。尽管这种方式从表面上看可以直接在Excel中像使用VBA一样使用这些编程语言,但从本质上看仍然是直接写xlsx文件。功能其实与第1种方式相同,因为这并不是官方支持的功能。
第3种是office.js,这是微软官方提供的一个基于JavaScript的程序库。基于Node.js,可以用JavaScript完全取代VBA实现Excel以及Office其他成员的加载项。office.js可以在Electron、Web应用以及大多数基于JavaScript的场景中使用。关于office.js的内容我以后会写文章详细描述,对office.js感兴趣的同学也可以关注“极客起源”公众号,会不定期更新这方面的内容。
 
32818-20200604151605942-623906739.png
4. macOS特有的集成方案:applescript
除了跨平台解决方案外,在macOS上,还支持使用applescript与Office(Excel、World、PowerPoint等)交互,这些内容我以后再撰写文章详细讲解。如果要了解excel applescript api,可以参考Excel Reference。从效果来看,applescript操作Office与在Windows下通过COM组件操作Office类似,可以完全控制Office,只是applescript的语法更接近自然语言。
下面的applescript代码会创建一个新的Excel文档,并将其保存为first.xlsx文件。
 
32818-20200604151633956-1643045524.png

 运行后,会看到一个打开的Excel文档,并且已经保存为firstx.xlsx文件。

 
32818-20200604151657859-1704056816.png

 5. Python与Excel集成,有哪些好处

Excel对于Python来说,可以将Excel看做是一个可编程的大组件。这个组件的主要功能就是可以制作任意复杂的报表和图表。尽管Python有很多模块可以制作报表和图表。但这些模块的功能和效果完全没办法与Excel相比。所以将Python与Excel结合的最大好处是可以快速完成制作报表的任务,而且效果杠杠滴。
将Python与Excel相结合,其实还会引出另外一个思考,就是成为专家还是通才的问题。我听到有很多程序员说,要将某种语言搞通,如PHP、Python、Java等,然后就可以很轻松解决所有的问题。结果真是这样吗?
很久以前,我听过一个关于微软的故事(相信很多人也听过),在微软有一个几十人的团队,花了好几个月还没完成一个项目,听说是遇到了某些难题。这时有一个老程序员(据说至少50岁以上)将自己关在办公室里一个星期,搞定! 我们先不管这个故事是真是假,那么从理论上来说,是否有这个可能呢?其实如果光看编程速度,再牛叉的程序员,也不可能比普通程序员快几十倍,更何况数百倍了。但还有另外一种可能,就是这名老程序员使用了完全不同的方法,绕过了大多数影响效率的因素,例如,使用了不同的工具,采用了不同的转换方式,甚至使用了不同的设计理念等等。这就不是能力问题了,而是认知的问题。我将其称为“认知虫洞”。
32818-20200604151738737-591880273.png

 所谓“认知虫洞”,是指通过某种方式很难完成某项工作,但通过另外完全不同,甚至是颠覆三观的方式,可以用极短的时间达到目的,而且效果极好。就像找到了可以穿越浩瀚星空的虫洞。这也有点像数学中的“等价替换”。

可能这个微软的例子离我们太远,下面举一个我自己的关于Excel例子,很多年前,我还在国内某大型软件公司作高级程序员。团队需要制作大量的报表,使用的主要开发工具是Delphi、后端是SQL Server数据库。Delphi本身有自己的报表系统,叫QuickReport。功能是很强大的,但问题是,做起来太费劲。例如,要画表格线时,如果一不小心将某根线拖到了别的地方,而且被其他东西覆盖,那你就找把,还必须要找到,否则打印出来的表格上就会莫名其妙多了根线。结果团队好几个人弄了好几天还没弄完(也包括我)。后来我实在不想这么弄了(因为买了几张影碟,着急回家看电影,不想加班),于是想到了利用Excel或Word来完成这个报表系统。通过Delphi传输数据。
说干就干,花了不到2个小时,所有的报表全部搞定(只有我一个人哦),几个人几天都没搞定的东西,我自己不到2个小时搞定,这当然不是我编程速度快了几十倍,而是处在了不同的维度,使用了完全不同的技术来实现,用QuickReport需要一根线一根线的画,而使用Excel,我不需要画线,只需要用SQL语句查询出数据,然后将这些数据发送给Excel即可。单单用了一个Excel,速度就提高了这么多,如果系统中很多部分都使用了类似的技术,那么编程效率提高数百倍,甚至上千倍,也不是没有可能的。
6. 了解多个技术领域,可以间接提高自己的IQ
可能有的同学会问,既然可以将多种技术结合起来大幅度提高开发效率,那么为什么不通过团队合作的方式来完成了,通常一个人无法学会那么多技术。其实这就是一个认知的问题,团队合作只有在项目所采用的技术被确定后,例如,如何集成多种技术,才可以发挥作用。问题是,如果多种知识分散在不同人的大脑中,很可能没有人意识到应该去这样融合多种技术,就更谈不上团队合作了,就像你要探索宇宙,首先你要知道存在宇宙这种东西,否则怎么去探索呢? 我将这种现象称为“认知孤岛”(相对于“认知虫洞”而言),就是说并不是没有能力去做,而是压根就没有意识到应该这样做(由于知识的缺乏、同时导致想象力的受限)。
32818-20200604151817918-1703295726.png
为什么达芬奇那么牛逼,除了聪明之外,达芬奇还横跨多个完全不同的领域,正是因为对生物学和解刨学的了解,蒙娜丽莎的画像才会那么自然,栩栩如生,因为达芬奇对骨骼、肌肉的构造非常了解,这是其他任何画家都无法比肩的。如果你在某一个领域排名前20%,而在另外一个领域排名也是前20%,那么如果需要两个领域的知识来解决问题时,你就会排名前4%(20% * 20%),如果是3个领域就是百里挑一。如果是6个领域,那就是万里挑一,据说达芬奇涉足十多个领域。由于自己和自己沟通的成本为0,所以只有拥有足够多的知识,并且有融合他们的能力,那么你就是下一个达芬奇!
32818-20200604151832957-2000862493.png

 我们可以举个数学与Python的例子:

 如果我们的程序需要计算某个表达式的定积分(例如y = 2 * x从0到1的定积分)。
32818-20200604151856579-1366351495.png
 假设我们使用的是Python语言,并且不太清楚有什么库可以自动计算定积分,那么采用的方式就是利用数值计算的方式写程序去完成,计算定积分的数值计算公式比较复杂,可能不是在短时间内能完成的。不过要是了解sympy这个库,那就是几行代码的事:
 
import sympy
x = sympy.Symbol('x')
f = 2 * x
# 开始计算定积分
print(sympy.integrate(f,(x,0,1)))

是不是很简单呢? 只需要了解一个API的用法就搞定了。

假设现在我们还有一个需求,要计算某个函数在某一点的导数(导数在深度学习中经常使用),而手头又没有必要的库(也有可能是不知道),那么只要了解导数的原理,就很容易通过几行代码搞定,这就属于高等数学的范畴了。
 
32818-20200604151942559-758548866.png

 导数原理,右侧是导数的计算公式,

# 计算导数的函数
def derivative(f,x):
  h = 0.0001   # x轴的增量,需要是一个很小的值,但要在浮点数精度范围内,通常不能超过小数点后6位
  return (f(x + h) - f(x - h)) / (2 * h)
# 待计算的函数1(y = 2 * x)  
def f1(x):
    return 2 * x
import math
# 待计算的函数2(  y = sin(x) * cos(x) / (sin(x) + cos(x))  )
def f2(x):
    return math.sin(x) * math.cos(x) / (math.sin(x) + math.cos(x))

print(derivative(f1,10))    # 1.9999999999953388
print(derivative(f2,123))   # -0.331842825692652
 PS:对这些代码和高等数学不熟悉也没关系,这里我只是举个例子,后期我会写一些关于数学和编程方面的文章,详细解释这些好玩的东西,可以关注我的公众号:极客起源 ,会不断更新各种技术和数学文章,以及视频课程。
从这两个案例可以看出,在某一个领域需要非常费劲才能搞出来的东西,在另一个领域其实就是hello world。如果了解足够多的领域,那么完成很多工作,就会表现出天才的特征(这也是成为天才的途径之一,另一个途径是投胎)。
 
32818-20200604152028990-1073529722.png

 PS:Excel的功能不仅仅是制作报表,Excel还拥有强大的数据分析能力。所以如果将Python与Excel集成,就意味着Python将拥有了Excel的全部能力,相当于Python拥有了Excel的整个生态。我将其称为“生态渗透”。也就是通过集成或其他方式,一种技术可以直接或间接使用另外一种技术的全部或大部分资源。

7. 提高开发效率的利器:生态渗透 
在未来,支持生态渗透的开发方式会非常普遍,如果只是用了一些现成的库或开源软件,并不能大幅度提高开发效率,但如果可以利用某些强大系统的生态,就不一样了。在未来,还会有很多支持“生态渗透”的开发工具。例如,我们团队研发的UnityMarvel,就是一款超平台开发系统。这里之所以称为“超平台”,而不是“跨平台”,是因为UnityMarvel不仅仅可以跨操作系统平台,还可以跨数据库平台,云平台、API平台、开源硬件、物联网等,以及支持虚拟SQL、客户端服务端一体化、柔性热更新、Office加载项、浏览器插件等新特性。因此称为“超平台”开发系统。并且自己研发了Ori编程语言(语法融合了Python、Java、Go等语言的优秀特性,但功能得到了前所未有的增强)。通过这些特性,可以用前所未有的规模利用其他系统的生态,要远比Python使用Excel的生态更完美。其他功能先不解释(等发布后我再写文章详谈),先说说UnityMarvel是如何跨数据库的。
所谓跨数据库(目前指关系型数据, 以后会支持文档、键值等NoSQL数据库),是指用UnityMarvel开发基于数据库的应用并不需要事先确定到底用什么数据库(如MySQL、SQL Server、Oracle等),UnityMarvel内置了一种虚拟数据库,可以直接用虚拟数据库开发,在发布时,会要求选择使用的数据库,例如,选择MySQL或SQL Server。UnityMarvel会通过rosetta引擎将Ori语言的代码转换为支持MySQL的代码。关于数据库的部分,主要是用过内置的一种虚拟SQL完成的,而且这种SQL语言是与Ori语言是融为一体的。例如,如果要从persons表中查询出id大于30的所有记录,可以直接这样写:
var  result = SELECT * FROM persons
                                 WHERE id > 30;
result的类型是SQLSelect,将result赋给Grid组件,就会直接显示查询结果。当发布时,会将上面的代码转换为使用相应数据库(如MySQL、SQL Server)的特定编程语言(如JavaScript、Java等)的代码。这么做的好处如下:
1. 不需要进行数据库选型,数据库是在发布时后期绑定的;
2. 如果想切换数据库(例如,从MySQL换成Oracle),只需要重新发布,选择相应的数据库就可以了,不需要修改一行代码;
3. 统一数据库接口,开发人员并不需要了解各种数据库的细节,开发门槛低;
4. UI与数据库交互非常容易,不必考虑各种数据库引擎和库,只需要直接将SQL语句赋给与其交互的UI组件即可;
5. 自动检测和去除大多数SQL中的潜在风险,如SQL注入等;
6. 脱离数据库环境开发。例如,想使用MySQL数据库开发,但当前机器上并没有MySQL开发环境,又不想安装MySQL。这时仍然可以用UnityMarvel内置的虚拟数据库进行开发,然后发布即可,部署在有MySQL环境的机器上就可以成功运行了;
32818-20200604152402020-1124711663.png
8. 上代码:Python到底如何与Excel交互
在这一节玩点真格的,看一看Python到底如何与Excel交互。我们使用目前最常用的openpyxl来完成操作。先看一个未处理的Excel表格。
32818-20200604152519810-1144870205.png
 上面这个表格是关于营业计划的数据,看起来很别扭,因为不同层次的数据之间没有缩进,也没有背景颜色,甚至没有表格线。如果要将这个表格交给领导,估计领导会拿起块砖头砸过来!
领导最希望见到下面的表格:
32818-20200604152539863-1851306959.png

 这个表格看起来是不是很舒服呢!其实这个表格用Excel做起来也并不费劲。不过仍然需要N步,这里就不详细解释如何用Excel来做这个表格了,现在来看如何利用Python闪电般进行格式转换。

from openpyxl.styles import Alignment,Font,Border,Side,Color,PatternFill
import openpyxl
# 打开待转换的文件
workbook = openpyxl.load_workbook('原始表格.xlsx')

ws = workbook.active
table = ws['A1':'D11']
# 设置字体
ft = Font(name="黑体")
for rows in table:
    for cell in rows:
        cell.font = ft
# 调整行高(所有的行的高度统一设置为18)
for i in range(1,ws.max_row + 1):
    ws.row_dimensions[i].height = 18.0
# 插入列
ws.insert_cols(1,1)

# 调整新插入列的宽度
ws.column_dimensions['A'].width = 5

# 插入行
ws.insert_rows(1,1)
# 调整新插入行的高度
ws.row_dimensions[1].height = 10


# 文字左对齐,数字右对齐
leftAlign = Alignment(horizontal='left',vertical='center')
rightAlign = Alignment(horizontal='right',vertical='center')
for row in ws.rows:
    for cell in row:
        # 数字,右对齐
        if type(cell.value) == int:
            cell.alignment = rightAlign
        else:
            cell.alignment = leftAlign

# 调整列宽
ws.column_dimensions['B'].width =20
ws.column_dimensions['C'].width =9
ws.column_dimensions['D'].width =9
ws.column_dimensions['E'].width =9
ws.column_dimensions['F'].width =4  # 让表格线出来一点



# 为表格添加边框

topBorder = Border(top=Side(border_style='thick',color='000000'))
                #bottom=Side(border_style='thick',color='000000'),
                #horizontal = Side(border_style='thin',color='000000'))
# 添加表格顶边的粗线(包括最后没有数据的列)
for col in range(2, ws.max_column + 2):
    ws.cell(2, col).border = topBorder

bottomBorder = Border(bottom=Side(border_style='thick',color='000000'))
# 添加表格底边的粗线(包括最后没有数据的列),这里需要加1,是因为前面绘制表格顶边的粗线时,最大列的数量已经多了1个
# 所以只需要加1即可
for col in range(2, ws.max_column + 1):
    ws.cell(ws.max_row, col).border = bottomBorder

# 添加水平细线
horizontalBorder = Border(top=Side(border_style='thin',color='000000'))
for col in range(2, ws.max_column + 1):
    for row in range(4,ws.max_row):
        ws.cell(row, col).border = horizontalBorder

# 单元格缩进
ws['B5'].alignment=Alignment(indent=1)
ws['B6'].alignment=Alignment(indent=1)
ws['B8'].alignment=Alignment(indent=1)
ws['B11'].alignment=Alignment(indent=1)

ws['B9'].alignment=Alignment(indent=2)
ws['B10'].alignment=Alignment(indent=2)

# 设置文字颜色
blueFont = Font(name="Arial",color = '4169E1')
for col in range(3, ws.max_column + 1):
    ws.cell(5, col).font= blueFont
    ws.cell(6, col).font = blueFont
    ws.cell(9, col).font = blueFont
    ws.cell(10, col).font = blueFont
# 设置背景色
fill = PatternFill("solid", fgColor="B0C4DE")
for col in range(2, ws.max_column + 1):
    ws.cell(4, col).fill= fill
    ws.cell(7, col).fill = fill
    ws.cell(12, col).fill = fill

workbook.save('转换后的表格.xlsx')

print('见证奇迹的时刻')
现在运行程序,当输出“见证奇迹的时刻”后,就会在当前目录生成一个“转换后的表格.xlsx”,该文件就是上图的效果,是不是很神奇呢?
从这段程序中可以看出,转换该表格需要多少步,代码并不复杂,大家可以根据openpyxl的文档研究。
9. 用Python替代VBA
目前微软官方还没有将Python作为VBA的替代品,倒是将JavaScript作为了另外一个选择(office.js),不过可以利用xlwings做一个折中。xlwings可以单独使用,也可以通过xlwings office加载项提供的RunPython函数运行Python代码。
现在有一个hello.py文件,代码如下:
import xlwings as xw
def hello_xlwings():
    wb = xw.Book.caller()
    wb.sheets[0].range("A1").value = "Hello xlwings!"
在xlwings的安装目录有一个xlwings.xlam文件,该文件是Excel的加载项文件,也就是Excel VBA的发行包文件。现在随便开启一个空的Excel workbook,然后点击“工具”>“Excel加载项”菜单项,会打开如下图所示的对话框,找到xlwings.xlam文件,并选中该文件。
32818-20200604152716337-883856747.png

 然后在“开发工具”选项卡中点击“Visual Basic”按钮(如下图所示),进入VBA编辑页面。

 
32818-20200604152742372-533187979.png

 最后引用xlwings库即可。

现在可以新建一个VBA模块,然后编写下面的代码:
 Sub test()
     RunPython ("import  hello; myproject.hello_xlwings()")
 End Sub   

运行脚本,就会看到在“A1”的位置插入了Hello xlwings!

OK,现在大家已经了解了如何使用Python与Excel交互,其他还有很多种方法,而且也不仅仅只有Python能与Excel交互,其实几乎所有的编程语言,甚至是C语言,都有想用的Library可以与Excel交互。那就期待我下面的文章吧!
 
32818-20200604153147191-1758815549.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK