加速你的Python代码

Posted on

加速你的Python代码

英文原文:Speeding Up Your Python Code,编译:oschina

在我看来,python社区分为了三个流派,分别是python 2.x组织,3.x组织和PyPy组织。这个分类基本上可以归根于类库的兼容性和速度。这篇文章将聚焦于一些通用代码的优化技巧以及编译成C后性能的显著提升,当然我也会给出三大主要python流派运行时间。我的目的不是为了证明一个比另一个强,只是为了让你知道如何在不同的环境下使用这些具体例子作比较。

使用生成器

一个普遍被忽略的内存优化是生成器的使用。生成器让我们创建一个函数一次只返回一条记录,而不是一次返回所有的记录,如果你正在使用python2.x,这就是你为啥使用xrange替代range或者使用ifilter替代filter的原因。一个很好地例子就是创建一个很大的列表并将它们拼合在一起。 1

2 3

4 5

6 7

8 9

10 11

12 13

14 15

16 17

18 19

20 import

timeit

import

random

def

generate(num): while

num:

yield

random.randrange(

10

) num

-

=

1

def

create_list(num):

numbers

=

[] while

num:

numbers.append(random.randrange(

10

)) num

-

=

1

return

numbers print

(timeit.timeit(

"sum(generate(999))"

, setup

=

"from main import generate"

, number

=

1000

))

>

0.88098192215

/#Python 2.7

>

1.416813850402832

/#Python 3.2

print

(timeit.timeit(

"sum(create_list(999))"

, setup

=

"from main import create_list"

, number

=

1000

))

>

0.924163103104

/#Python 2.7

>

1.5026731491088867

/#Python 3.2

这不仅是快了一点,也避免了你在内存中存储全部的列表!

Ctypes的介绍

对于关键性的性能代码python本身也提供给我们一个API来调用C方法,主要通过 ctypes来实现,你可以不写任何C代码来利用ctypes。默认情况下python提供了预编译的标准c库,我们再回到生成器的例子,看看使用ctypes实现花费多少时间。 1

2 3

4 5

6 7

8 9

10 11

12 13

14 import

timeit

from

ctypes

import

cdll

def

generate_c(num): /#Load standard C library

libc

=

cdll.LoadLibrary(

"libc.so.6"

)

/#Linux /#libc = cdll.msvcrt /#Windows

while

num: yield

libc.rand()

%

10

num

-

=

1

print

(timeit.timeit(

"sum(generate_c(999))"

, setup

=

"from main import generate_c"

, number

=

1000

))

>

0.434374809265

/#Python 2.7

>

0.7084300518035889

/#Python 3.2

仅仅换成了c的随机函数,运行时间减了大半!现在如果我告诉你我们还能做得更好,你信吗?

Cython的介绍

Cython 是python的一个超集,允许我们调用C函数以及声明变量来提高性能。尝试使用之前我们需要先安装Cython. 1 sudo pip install cython

Cython 本质上是另一个不再开发的类似类库Pyrex的分支,它将我们的类Python代码编译成C库,我们可以在一个python文件中调用。对于你的python文件使用.pyx后缀替代.py后缀,让我们看一下使用Cython如何来运行我们的生成器代码。

1

2 3

4 5

6 7 /#cython_generator.pyx

import

random

def

generate(num): while

num:

yield

random.randrange(

10

) num

-

=

1

我们需要创建个setup.py以便我们能获取到Cython来编译我们的函数。

1

2 3

4 5

6 7

8 from

distutils.core

import

setup

from

distutils.extension

import

Extension from

Cython.Distutils

import

build_ext

setup(

cmdclass

=

{

'build_ext'

: build_ext}, ext_modules

=

[Extension(

"generator"

, [

"cython_generator.pyx"

])]

)

编译使用:

1 python setup.py build_ext

-

-

inplace

你应该可以看到两个文件cython_generator.c 文件 和 generator.so文件,我们使用下面方法测试我们的程序:

1

2 3 import

timeit

print

(timeit.timeit(

"sum(generator.generate(999))"

, setup

=

"import generator"

, number

=

1000

))

>

0.835658073425

还不赖,让我们看看是否还有可以改进的地方。我们可以先声明“num”为整形,接着我们可以导入标准的C库来负责我们的随机函数。

1

2 3

4 5

6 7

8 /#cython_generator.pyx

cdef extern

from

"stdlib.h"

: int

c_libc_rand

"rand"

()

def

generate(

int

num):

while

num: yield

c_libc_rand()

%

10

num

-

=

1

如果我们再次编译运行我们会看到这一串惊人的数字。

1 >>>

0.033586025238

仅仅的几个改变带来了不赖的结果。然而,有时这个改变很乏味,因此让我们来看看如何使用规则的python来实现吧。 PyPy的介绍PyPy 是一个Python2.7.3的即时编译器,通俗地说这意味着让你的代码运行的更快。Quora在生产环境中使用了PyPy。PyPy在它们的下载页面有一些安装说明,但是如果你使用的Ubuntu系统,你可以通过apt-get来安装。它的运行方式是立即可用的,因此没有疯狂的bash或者运行脚本,只需下载然后运行即可。让我们看看我们原始的生成器代码在PyPy下的性能如何。

1

2 3

4 5

6 7

8 9

10 11

12 13

14 15

16 17

18 19

20 import

timeit

import

random

def

generate(num): while

num:

yield

random.randrange(

10

) num

-

=

1

def

create_list(num):

numbers

=

[] while

num:

numbers.append(random.randrange(

10

)) num

-

=

1

return

numbers print

(timeit.timeit(

"sum(generate(999))"

, setup

=

"from main import generate"

, number

=

1000

))

>

0.115154981613

/#PyPy 1.9

>

0.118431091309

/#PyPy 2.0b1

print

(timeit.timeit(

"sum(create_list(999))"

, setup

=

"from main import create_list"

, number

=

1000

))

>

0.140175104141

/#PyPy 1.9

>

0.140514850616

/#PyPy 2.0b1

哇!没有修改一行代码运行速度是纯python实现的8倍。

进一步测试为什么还要进一步研究?PyPy是冠军!并不全对。虽然大多数程序可以运行在PyPy上,但是还是有一些库没有被完全支持。而且,为你的项目写C的扩展相比换一个编译器更加容易。让我们更加深入一些,看看ctypes如何让我们使用C来写库。我们来测试一下归并排序和计算斐波那契数列的速度。下面是我们要用到的C代码(functions.c): 1

2 3

4 5

6 7

8 9

10 11

12 13

14 15

16 17

18 19

20 21

22 23

24 25

26 27

28 29

30 31

32 33

34 35

36 37

38 39

40 41

42 43

44 45

46 47

48 49

50 // functions.c //

/#include /#include

/#include

// http://rosettacode.org/wiki/Sorting_algorithms/Merge_sort/#C // inline

void

merge (

int

/*left,

int

l_len,

int

/*right,

int

r_len,

int

/*out) {

int

i, j, k; for

(i = j = k = 0; i < l_len && j < r_len;)

out[k++] = left[i] < right[j] ? left[i++] : right[j++]; while

(i < l_len)

out[k++] = left[i++]; while

(j < r_len)

out[k++] = right[j++]; }

// inner recursion of merge sort //

void recur (

int

/*buf,

int

/*tmp,

int

len)

{ int

l = len / 2;

if

(len <= 1) return

;

// note that buf and tmp are swapped // recur (tmp, buf, l);

recur (tmp + l, buf + l, len - l); merge (tmp, l, tmp + l, len - l, buf);

}

// preparation work before recursion // void

merge_sort (

int

/*buf,

int

len) {

// call alloc, copy and free only once // int

/*tmp =

malloc

(

sizeof

(

int

) /* len);

memcpy

(tmp, buf,

sizeof

(

int

) /* len); recur (buf, tmp, len);

free

(tmp); }

int

fibRec (

int

n) {

if

(n < 2) return

n;

else return

fibRec (n - 1) + fibRec (n - 2);

}

在Linux平台,我们可以用下面的方法把它编译成一个共享库:

1

2 gcc

-

Wall

-

fPIC

-

c functions.c

gcc

-

shared

-

o libfunctions.so functions.o

使用ctypes, 通过加载”libfunctions.so”这个共享库,就像我们前边对标准C库所作的那样,就可以使用这个库了。这里我们将要比较Python实现和C实现。现在我们开始计算斐波那契数列:

1

2 3

4 5

6 7

8 9

10 11

12 13

14 15

16 17

18 19

20 21

22 23 /# functions.py

from

ctypes

import

/*

import

time

libfunctions

=

cdll.LoadLibrary(

"./libfunctions.so"

)

def

fibRec(n): if

n <

2

:

return

n else

:

return

fibRec(n

-

1

)

+

fibRec(n

-

2

)

start

=

time.time() fibRec(

32

)

finish

=

time.time() print

(

"Python: "

+

str

(finish

-

start))

/# C Fibonacci

start

=

time.time() x

=

libfunctions.fibRec(

32

)

finish

=

time.time() print

(

"C: "

+

str

(finish

-

start))

正如我们预料的那样,C比Python和PyPy更快。我们也可以用同样的方式比较归并排序。

我们还没有深挖Cypes库,所以这些例子并没有反映python强大的一面,Cypes库只有少量的标准类型限制,比如int型,char数组,float型,字节(bytes)等等。默认情况下,没有整形数组,然而通过与c_int相乘(ctype为int类型)我们可以间接获得这样的数组。这也是代码第7行所要呈现的。我们创建了一个c_int数组,有关我们数字的数组并分解打包到c_int数组中

主要的是c语言不能这样做,而且你也不想。我们用指针来修改函数体。为了通过我们的c_numbers的数列,我们必须通过引用传递merge_sort功能。运行merge_sort后,我们利用c_numbers数组进行排序,我已经把下面的代码加到我的functions.py文件中了。 1

2 3

4 5

6 7

8 9

10 11

12 13

14 15

16 17

18 19

20 21

22 23

24 25

26 27

28 29 /#Python Merge Sort

from

random

import

shuffle, sample

/#Generate 9999 random numbers between 0 and 100000 numbers

=

sample(

range

(

100000

),

9999

)

shuffle(numbers) c_numbers

=

(c_int

/*

len

(numbers))(

/*

numbers)

from

heapq

import

merge

def

merge_sort(m): if

len

(m) <

=

1

:

return

m middle

=

len

(m)

/

/

2

left

=

m[:middle] right

=

m[middle:]

left

=

merge_sort(left) right

=

merge_sort(right)

return

list

(merge(left, right))

start

=

time.time() numbers

=

merge_sort(numbers)

finish

=

time.time() print

(

"Python: "

+

str

(finish

-

start))

/#C Merge Sort

start

=

time.time() libfunctions.merge_sort(byref(c_numbers),

len

(numbers))

finish

=

time.time() print

(

"C: "

+

str

(finish

-

start))

1

2 3

4 5

6 7

8 Python:

0.190635919571

/#Python 2.7

Python:

0.11785483360290527

/#Python 3.2 Python:

0.266992092133

/#PyPy 1.9

Python:

0.265724897385

/#PyPy 2.0b1 C:

0.00201296806335

/#Python 2.7 + ctypes

C:

0.0019741058349609375

/#Python 3.2 + ctypes C:

0.0029308795929

/#PyPy 1.9 + ctypes

C:

0.00287103652954

/#PyPy 2.0b1 + ctypes

这儿通过表格和图标来比较不同的结果。

加速你的Python代码 Merge Sort Fibonacci Python 2.7 0.191 1.187 Python 2.7 + ctypes 0.002 0.044 Python 3.2 0.118 1.272 Python 3.2 + ctypes 0.002 0.046 PyPy 1.9 0.267 0.564 PyPy 1.9 + ctypes 0.003 0.048 PyPy 2.0b1 0.266 0.567 PyPy 2.0b1 + ctypes 0.003 0.046

希望你利用C和PyPy优化你的python代码并以此为敲门砖找到一个好职位。像往常一样如果你有任何意见或问题,请随时把评论下载下面或者在我的网页上与我取得联系。感谢您的阅读!

附:如果您的公司正在寻求聘请即将毕业的优秀大学生(2013年5月),让我知道! 来源: [http://blog.jobbole.com/36701/](http://blog.jobbole.com/36701/)

MongoDB 客户端 MongoVue

Posted on

MongoDB 客户端 MongoVue - 张善友 - 博客园

自由、创新、研究、探索

Linux/Windows Mono/DotNet [ Open Source .NET Development/使用开源工具进行DotNet软件开发]

MongoDB 客户端 MongoVue

今天在同事那里看到了一个很不错的MongoDB的客户端工具MongoVue,地址是http://www.mongovue.com/。做的不错,1.0版本的开始收费了,费用也不贵才35$。真正需要的同学可以掏点钱买个吧,也算是支持这个工具,如果只是学习研究用的话我这里还有一个0.9.7版本,虽然比起1.0版来说有些bug,平常使用也够了,需要的同学可以单独联系我。

1.0版之后超过15天后功能受限。可以通过删除以下注册表项来解除限制:

[HKEY_CURRENT_USER\Software\Classes\CLSID{B1159E65-821C3-21C5-CE21-34A484D54444}\4FF78130]

把这个项下的值全删掉就可以了。

下面上图给大家感受下强大的MongoVue,可以提高你使用MongoDB的幸福指数好几十点,上图是王道:

1、配置连接

image

2、试下新建一个名为AccessLog的Collection :

image

image

3、插入一个Document

image

4、查看我们插入的数据,数据可以通过多种方式展示(树形、表格、文本)

image

上面我们都是通过图形界面的操作的吧,下面有一个窗口列出了上述操作的客户端命令哦,这是学习的好资源,在用图形界面的时候依然可以学习熟悉下命令行。

image

当然上述只是介绍了下最基本的功能,还有更新,删除数据库,从mysql数据库导入数据等等功能,想了解更详细的内容请访问官方网站:http://www.mongovue.com/

http://blog.nosqlfan.com/tags/mongodb

posted @ 2011-05-20 21:57 张善友 阅读(12667) 评论(71) 编辑 收藏

刷新评论刷新页面返回顶部

博客园首页博问新闻闪存程序员招聘知识库

公告

Copyright ©2013 张善友

MongoDB基础问题及使用方式

Posted on

MongoDB基础问题及使用方式-随风飘云-ChinaUnix博客

Chinaunix首页 |  论坛 |  博客 登录 | 注册

博文 博主

随风飘云的ChinaUnix博客

一无所有,随风飘荡

随风飘云

  • 博客访问: 453761
  • 博文数量: 140
  • 博客积分: 2739
  • 博客等级: 少校
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-07 12:28 *

文章分类

全部博文(140)

2012年(71)

2011年(69)

我的朋友

hbxmadco

vinhlam

mutalip

金色の闪

dong1892

chianace

niao5929

split_tw

manfred_ 最近访客

ghan

zongg

订阅

热词专题

** MongoDB基础问题及使用方式 2012-08-09 18:06:38

分类: 数据库开发技术

MongoDB基础问题及使用方式

            这是在学习MongoDB时网上找的一篇不错的文档,做为保存。

1.linux 系统:

1】关闭文件系统/分区的atime 选项 Vi /etc/fstab

在对应的分区项后面添加noatime ,nodiratime LABEL=/1 / ext3 defaults 1 1

LABEL=/data1 /data ext4 defaults,noatime,nodiratime 1 2 2】设置文件句柄4k+,目前该配置已经集成到启动脚本中。

Vi /etc/security/limit.conf /* soft nproc 65536

/ hard nproc 65536 / soft nofile 65536

/* hard nofile 65536 3】不要使用large vm page (不要使用大内存页选项)

Linux 大内存页参考:http://linuxgazette.net/155/krishnakumar.html 4】用dmesg 查看主机的信息。

2.linux 文件系统的选择: Mongodb 采用预分配的大文件来存储数据,我们推荐

1】ext4 2】xfs

3.内核版本: 网络上对2.6.33-31 以及2.6.32 的表现持怀疑度, 而强力推荐2.6.36

4.线程堆栈的尺寸 默认的线程堆栈尺寸为10m ,调整为1m ,已经集成在启动脚本中。

项目过程中的总结与建议 1.大小写问题

mongodb 是默认区分大小写的,但是这会不会衍生出跟mysql 一样的问题?(mysql 区 分大小写,导致windows 与linux 下的表名,字段名不一致)。

如果无特别用途,建议表名,字段名全部用小写字母。 2.尽可能的缩短字段名的长度

mongodb 的schema free 导致了每笔数据都要存储他的key 以及属性,这导致了这些数 据的大量冗余。开发同事也许考虑到,从易读性出发设计的key 基本比较长,基本都是按

照起字面意思去设计的。这导致key 很长。对应的数据存储占用了很大的空间。 必要的时候,可以考虑建立一个key 与实际意义的map 表,尽量降低key 的长度。

示例定义: // 基本信息

static final String _ID = "_id"; static final String STATUS_CODE = "sc";

// 缓冲 static final String DATE = "date";

static final String MAX_AGE = "age"; // 内容

static final String CONTENT = "content"; static final String CONTENT_TYPE = "ctype";

static final String CONTENT_LENGTH = "clen"; static final String ZIP = "zip";

  1. mongodb 单表最大索引数为64 无索引排序的最大数据量为4M, 超过则报错退出。

建议where 条件尽量落在索引字段上,排序字段需要建立索引,索引的使用原则与oracle mysql 一致,尽量降低索引数量,索引长度。

mongodb 的查询每次只能用到一个索引,对数据的查询不会“并发”执行 例如: db.tab.find({'id'=1,'name'=2}) 如果‘id’,‘name' 列上分别有索引

对查询效率提升意义不大,如果索引为('id','name') 则大幅提升效率。 4.mongodb 添加字段

如果添加字段且带有default 值,需要全部数据都要修改,这也是设计阶段需要考虑的 事情,这个问题的另外一种解法是应用代码里做一次判断。

5.测试过程的密码问题 对于用作数据库使用的Mongodb,在代码测试阶段都应加上密码验证,目前上线阶段基

本都会在密码验证方面出现问题(做缓存使用的可以不做密码验证)。 6.数据源连接方式

使用连接池模式,尽量减少认证带来的性能额外消耗 建议采用标准的uri 连接方式: mongodb://user:passwd@host:port,host:port/db

7.Mongodb日志量 正常情况下不需要开启-v 日志选项。

Mongodb 的-v 日志适合在开发环境的调试线上部署不建议采用这个参数,目前线上 部署的情况,-v 日志一天也会有几个G 的日志量,去掉这个参数,跟数据查询相关的操作

就不会记日志了,数据库的内部的重要操作还是会写日志的。 8.连接数大小的设置

Mongodb 驱动程序采用的连接池的方式连接到数据库,目前从观察到的情况是应用一 开启便根据变量的设置,建立全部连接,然后提供给程序使用,并且一旦其中某个连接

到数据库的访问失败,则会清空整个连接池到这台数据库的连接,并重新建立连接。 而mongodb 对中断连接的垃圾清理工作则是懒惰的被动清理方式,如果驱动程序端配

置的连接数过大,一旦发生重连,则会导致mongo 端堆积大量的垃圾连接数据,导致 主机资源耗尽。

建议: mongodb 驱动的连接池大小的设置一般应该控制100 以下,一般情况30-50 足 够支撑应用访问。

9.锁的问题 Mongodb 对数据库的访问全部加锁,如果是查询请求则设置共享锁,数据修改请求,

则设置全局排他锁,并且是实例级别的排他锁。并且写锁会阻塞读请求,如果长时间持有 写锁,会阻塞整个实例的读请求。

部署建议: 1】一般情况下,建议不同的应用不要合用一套示例。

2】如果资源不满足,需要合用,应该具有相同属性的应用合用一套实例。 例如合同mongo 的应用都是读多写少,防止一台写多应用阻塞读请求。

10.关于map/reduce问题 mongodb 对map/reduce 的支持是单线程的,我们不建议在前台使用该功能, group by

是通过map/reduce 实现的,开发过程中,要慎用。 11.安全问题

1】Mongodb 运行在mongodb 用户之上,并禁止mongodb 用户登录 2】使用Mongodb 自带的认证方法(adduser、auth)限制用户访问行为

3】将Mongodb 置于内网环境中 4】Mongodb 必须暴露在外网环境中的时候,使用IPTABLES 等网络层技术进行防护

5】网络层面内容为明文传输,可以考虑存储加密文档,应用端,加解密。 12.性能监控

Mongodb 自带有性能数据收集系统 Mongostat 实时采集数据库的多项指标,提供http console 端口号为应用端口号+1000。

关注的主要性能指标: 1】Faults:显示Mongodb 每秒页面故障的数量,这个是mongoDB 映射到虚拟地址空间,

而不是物理内存,这个值如果飙高的话,可能意味着机器没有足够的内存来 存储数据和索引。

2】Flushes:每秒做了多少次fsync,显示多少次数据被刷新进了磁盘 3】locked:写锁

4】idx miss:索引未命中比例 5】qr | qw:读写锁的请求队列长度。

6】conn: 当前已经建立的连接数。 其他命令:

Db.stat() db.serverStatuse()

Db.collection.stats() 13.碎片问题

Mongodb 数据库如果数据修改很频繁,会出现比较严重的空间碎片问题,表现在磁盘 文件扩张与实际数据量不相符,内存不够用,索引命中率低,查询效率降低。

碎片整理,目前我们采用的版本没有太有效的方法。 可以用db.repaireDatabase() 来整理数据库,这个过程非常的慢

如果是Master-slave 模式则相当于执行一次主从切换,然后从新建立从库。 如果是replSet 架构可以停掉数据库,然后删除数据目录,从新从复制复制组中全同步数据,

这个时候要考虑oplog 的尺寸。 一个大体的步骤:

1.】先调用rs.freeze(1200),将每个不想让它成为primary 的机器让它在1200 秒内无法成为 primary(这步也可以不做)

  1. 】将primary stepDown,不出意外新的primary 会起来.
  2. 】将原primary kill 掉.

  3. 】删掉所有data 数据(调用repair 很慢,真不如干掉重新来)

  4. 】再重启动原primary 的进程

  5. 】以此循环完成整个复制组的全部重建。 14.系统备份:

Mongodb 目前不支持在线备份,只能离线备份。 我们采用的架构为replSet 和Master-slave .

基于我们目前的架构以及数据一致性要求,我们没有安排相关的备份系统。 15.应用代码中Mongodb连接问题

在有些应用在使用Mongodb 过程中会存在以下两个小问题:

  1. 在应用启动过程中,应用存在要求连接池中所有的连接都建立成功才让应用正

常启动,这种做法不可取,因为存在网络问题、Mongodb 拒绝连接或Mongodb 假死情况,如果没加外部try catch 做防护,则Resin 不断重启也不能正常启动端口。 2.有些应用在使用Mongodb 中连接池配置了safe=true,w=1;这种配置意味着客户端在

插入数据或更新数据的时候,要求mongodb 必须将所更新的数据写入磁盘并返回更新成功的信息给程序。如果碰上应用程序访问压力大,mongodb 就会反应迟钝,并会发生假死可能,针对此情况,需要评估数据的一致性需求,做出合适调整。我们一般建议关闭此选项。 16.补充开发方面的一些问题

1】skip+limit翻页,越往后面越慢,有资料说用数组元素的分页可以解决,目前还没 试过,比较靠谱的做法是,先找出上次的id,翻页的时候不用skip:

last_row_id = ObjectId(‘....’); db.activity_stream->find({_id:{$lt: last_row_id },

user_id:20 } ).sort( {_id:-1} ).limit(10); 2】.只有真正需要的字段才select出来

3】.更新的某条数据的时候,先查出来再更新会减小锁的时间 4】.只有返回很少结果的查询才用索引,否则会加载太多数据,比没有用索引还慢

5】.属性比较多的时候,建立分层的关系能够提高查询效率,否则每个记录都要过一遍 才能找到要的属性

17.关于硬件资源的选择: 虚拟机可以很好的隔离资源,并可动态的扩展。

我们建议mongodb 的部署采用虚拟机的方式,每个虚拟机部署一个实例,使各节点分 散在不同的物理机上,根据应用的前期预测,平衡虚拟机的之间的i/o。 阅读(392) | 评论(1) | 转发(0) |

0

上一篇:MongoDB的大数据的存储方式

下一篇:MongoDB翻译-() 相关热门文章

给主人留下些什么吧!~~

随风飘云2012-08-09 18:08:43

回复 | 举报 评论热议

请登录后评论。

登录 注册

关于我们 | 关于IT168 | 联系方式 | 广告合作 | 法律声明 | 免费注册

Copyright 2001-2010 ChinaUnix.net All Rights Reserved 北京皓辰网域网络信息技术有限公司. 版权所有

感谢所有关心和支持过ChinaUnix的朋友们

京ICP证041476号 京ICP证060528号

X

分享到...

选择其他平台 >> 分享到X

腾讯微博

QQ空间 新华微博

凤凰微博 开心网

豆瓣网

一键通

搜狐微博 天涯

网易微博 人民微博

QQ好友 新浪微博

人人网 手机

朋友网 百度空间 更多平台... (130)

bShare

我6个月的学习编程经历:从”大齿怪“到“狂欢者”

Posted on

我6个月的学习编程经历:从”大齿怪“到“狂欢者”

#

The Noob

Almost exactly six months ago, I decided to embark on an adventure. Before October of 2010, I had never programmed a day in my life. Okay maybe I had a week-long unit on the very very very basics in sixth grade. But that is all. I had no idea what to expect. October 19th, 2010, I tweeted: “What have I gotten myself into. I’ve just embarked on learning programming, having absolutely no experience. Oh man I’m already nervous.” That was the beginning of a path that I’m so glad I have taken. I’m not looking back.

Beginnings

I’m going to give you a quick overview of my first few months, because it was pretty boring. I started with Invent with Python, a really awesome book for complete noobs. To show you how beginner it was, here is a quote from the book: The + sign tells the computer to add the numbers 2 and 2. To subtract numbers use the – sign, and to multiply numbers use an asterisk (/*).

After I got the very basics down, I made a bunch of random text-based games, like hangman, jotto, and guess-the-number. My first big hit was a game called “The Man-Rodent.” It was about a Man-Rodent, whatever the hell that is, who was terrorizing the village. He was hiding, and you had to guess where he was:

This was also when I received my first piece of cherished fan art. I posted the game on Reddit and Michael Hussinger made this AMAZING cover art for it:

Next, I moved on to my first quasi-graphics based game: Minesweeper. This is when I really started to understand why creating a flexible game engine is really important (yeah, like I created a game engine). The game was still text-based, but it was completely flexible, in that I could specify board size and mine amount. This ended up giving it some replayability and it was fun to play around with crazy numbers just to see what happened. Here’s that game:

Welcome to iOS

At this point, I felt I was ready to move on to actual graphics. I felt at an impasse. I had absolutely no idea where to start. I took a look at SDL but was in way over my head and got quickly discouraged. Since I knew I eventually wanted to make an iPhone app, I asked Matt Rix (Trainyard), who gave me some sage advice. He recommended I start by learning C, then Objective-C, then Cocos2d. I’m happy to say that as of today, I’ve learned all three of those! The basics anyway.

During the period of learning the basics of C and Obj-C, I came across a lot of frustrations and I didn’t make many games. Many times, I really wondered if I could ever get past the hurdle and figure it out. A few of the things that I pulled my hair out over when I first learned of them: structs, arrays, multi-dimensional arrays, properties, views, view controllers, protocols and delegates, memory management and many more. And there is still so much out there that is way over my head. But I’m going to keep trucking because everyone I talk to says the only way to get better is to just keep making games. Being a piano player, I am well aware that practice pays off, so that’s what I’ve been doing (and will keep doing).

Welcome to Cocos2d

Once I finally got the basics of creating an iPhone app down, I was ready to delve into Cocos2d. I was nervous but excited. Now, I don’t know if I’m crazy or stupid but I have found that the Cocos2d documentation is not very good. All the classes, methods, and properties are listed, but I am constantly struggling to understand things because they are not explained well. An example: every “node” (the main Cocos2d element) has a “(BOOL) isRunning” property. It sounds simple enough, but it could easily mean any number of things. All the documentation says about this property is: “whether or not the node is running.” Uh, okay . . . Needless to say, I’m still pretty confused about a fair amount of things in Cocos2d.

But enough of the insults. I am loving Cocos2d. Once I got a hang of the basics, I started to see how much easier it was to get a simple game up and running in no time. And since I already know how to do music and sound, and also know a little bit of Photoshop, I was really starting to see some pretty cool results. Since I was really confused by Cocos2d at first, I started with a few of Ray Wenderlich’s awesome tutorials.

A Bunch of Sorta-Games I’ve Made

Here is my first Cocos2d game, which I created by directly following Ray’s tutorial (it even had my own music and stupid sound effects for when an enemy died!):

Next, I made a Pong clone. It even had multiplayer!:

After Pong, I was feeling encouraged, and decided to try to make Tetris. Big mistake. I was not ready. I ran into a lot of really annoying errors and bugs, and when I finally got the basic framework down, I tweeted something like: “So proud of myself. I just created a really complex class/subclass system for my Tetris clone.” Noel Llopis quickly informed me how bad of an idea that was. So I looked at some tutorials and tried to completely revamp my Tetris clone, but it was still too difficult. I will return and defeat you one day, Tetris!

After my failed attempt at Tetris, I made a little Tilt to Live inspired prototype, except in this version, you get points for collecting red dots, instead of avoiding them. And this one didn’t have the music I did for the real game (that is a link to the Tilt to Live soundtrack. Buy it now or red dots will eat you while you sleep.):

After a lot more learning of Cocos2d, I had a random inspiration to make an endless crumpled paper background. So I crumpled paper and made it an endless background. Then I put a little paper circle in the game that you could roll around using the accelerometer. I was really proud of myself when I figured out how to roll the circle because it involved some math that I hadn’t done in a long time (even though it was fairly simple trigonometry). The background was buggy – there were frequently gaps between the images of the repeating background – but it worked:

Next, after seeing a trailer for the awesome looking upcoming game Bumpy Road, I got inspired and wondered if I could recreate an effect similar to its bumpy road element. Needless to say, my graphics were a bit more barren, but you can compare.

Bumpy Road:

My version:

After this, I wanted to try my hand at actually animating something. I had never animated anything before and gave it a go on Photoshop. Man was it tedious. Even for just a stupid little line drawing. But what I came up with was who I like to call PARTYMAN. All he did was open and close his mouth over and over again, each time making a randomly chosen grunt noise. You could also move him around the screen. And the background flashed different colors. And he only grunted and partied when you were actually touching the screen:

Somehow, PARTYMAN gained a small following. I think he might be next in the long list of icons including Mario, Link, Samus, and others. I actually ended up sending a copy to Jared of Touch Arcade (hey, he asked for it). Then, to my great surprise and utmost joy, Craig Sharpe of Retro Dreamer created my second official piece of fan art! Here is Craig’s AWESOME take on PARTYMAN:

His drawing was so awesome, in fact, that I had to include it in one of my next games. But first, on a whim I started making a game about a guy jumping over poles. The original point was just to see if I could make a parallax background with a simple game mechanic, but I just kept going with it. It ended up having a title screen, score-tracking, replayability, music, sounds, variable jump heights, a jump height progress bar indicator, and even a credits page! It was my most complete game yet. I drew some pretty awful sprites for my game, as you can see here:

Since my drawings sucked, I asked Michael Hussinger (of “The Man-Rodent is in the Barn” fame) if he wanted to do a few quick doodles for it, and he did! He drew this awesome pizza guy in probably 20 minutes. It would take me hours upon hours to draw something that good, if I even could at all. He also drew a nice mountainous background for my parallax scrolling. Here’s how the game looked after his help, along with my title and credits pages:

The game in action!

My next game was inspired by Trainyard. I wanted to see if I could create a grid that I could draw roads on that a vehicle would follow. What better opportunity for a return of PARTYMAN, right? So I called it Partybus. The point of the game was to click a spot on the grid to make a party (a flashing, color-changing spot with music coming out of it), then to draw a road to the party and have PARTYMAN drive there in his Partybus. Needless to say, it was a really easy game. But the cool thing is, when he reached his party destination, the music got louder and bassier, the bus started doing a dance, and Craig’s fan art of him appeared above the bus and started shaking to the beat!

The code was very buggy and pretty damn broken. I tried to have my brother play the app and it took him three tries to do anything at all because he would click the wrong square at the wrong time and it would basically ruin the game. And I would have to completely restart the app each time because I didn’t build in a “restart” feature. But I was still pretty proud of my crappy Trainyard ripoff. Matt should pay me for it.

My next project was a Snake clone. I found this tutorial on how to build Snake in flash and basically just ported it to iPhone. It gave me a lot of insight into how to make this game. Before the tutorial, I was planning on having the snake move once per frame, but was having a lot of trouble figuring out how to make his tail follow him. I was considering building up an array of all the past moves and assigning them to each of his tail pieces every tick, but that would have gotten really annoying really fast. This tutorial flipped my world upside down when I realized the Snake was not actually moving. Instead, the illusion of movement was given by simply adding and removing snake pieces from the grid on every frame. Then, when you picked up an apple, all it did was tell the program not to remove any pieces for five turns. I need to remake this game for sure, because the UI sucked, the controls were awful, and the code was pretty messy due to my hacked together port. But for a basic Snake game it turned out pretty well!

After Snake I tried making Partybus 2: Partyman’s Big Weekend. I got a little further than before. Ended up adding a speed slider like in Trainyard, a depot that the train could leave from, sound effects (when he crashed there was the sound of a massive car accident and he yelled “No partying today!”) and just overall cleaner code. But again, I soon ran into entangled code and whenever I tried to fix one thing, another thing wouldn’t work. My biggest problem was that when I set the speed slider all the way to its highest value, the bus would crash at a random joint in the road. This was due to the updates being called too often and the code not updating enough before the next tick. Even though I sort of knew what the problem was, it would take too much work to go back and fix it. I think I will have to make a Partybus 3: The Final Party.

My most current project is a remake of Doodle Jump. So far it’s coming along quite nicely. I have platforms that keep moving higher and higher, a jumper guy, some items (well, so far only a spring), custom music and sounds, and a UI that totally rips off the original game. I’m pretty happy with this one so far. I’m going to try to keep adding a bunch of stuff to it.

Conclusion

It truly is amazing how much practice helps. Every time I write a new program, I run into a ton of unforeseen problems and bugs. While frustrating at the time, I usually plan around them the next time I program. This makes me feel like I’m in my very own while loop:

while (stillPrettyBadAtProgramming) { programmingPracticeTime++; Program /*newProgram = [Program programWithType:ProgramTypeGame]; if (newProgram.isReallyGood == YES && programmingPracticeTime >= A_HUGE_AMOUNT) { stillPrettyBadAtProgramming = NO; } }

I’m going to keep creating. It’s been a blast so far, and I can’t wait to see what the next six months entails. Be sure to return next time, when I will talk about the long process that went into making the music (and a few sounds) for Casey’s Contraptions!

来源: [http://www.whitakerblackall.com/blog/first-six-months/](http://www.whitakerblackall.com/blog/first-six-months/)

我是菜鸟

几乎刚好是6个月前,我决定开始从事一项新的职业。2010年10月之前,我从未接触过编程。要说有,那也只是在6年级时学过了大概一周的非常基 本、基本、基本的编程知识。就这些。我不知会学成什么样。2010年10月9日我在微博上写道:“我究竟想干吗?我决定学习编程,我没有任何的基础。唉, 兄弟们,我有些担心。”这是一段生涯的开始,我很高兴能走上这条路。我不会回头。

开端

我将只快速简单的给你们讲一下我前几个月的学习过程,因为这段时间非常的枯燥。我从Invent with Python这本书开始,这是一本对新手来说非常不错的教程。为了让你们知道它是如何的初级,我向你们展示这本书里的一段话:

  • 这个符号是来告诉计算机把2和2相加。做减法用这个符号 -,做乘法用星号(/*)。

在我学会了一些非常基本的知识后,我随意的做了很多文本形式的小游戏,比如刽子手,jotto,猜数字。我的第一个比较大一点的小玩意叫做“大齿怪”。这个游戏的情景是关于一个大齿怪(就把它想成一个怪物吧),祸害村里。它藏在什么地方,你需要去猜它在哪:

也就是在此时我收到了我的第一张珍贵的粉丝画的作品。我把这个游戏发布在了Reddit上,Michael Hussinger为它制作了这张令人惊叹的封面画:

接下来,我转移到了我的第一个半图形游戏:”扫雷“。在此时我才开始真正的理解构造一个灵活的游戏引擎有多么的重要(没错,就像我开发的这个游戏引 擎)。这个游戏仍然是文本形式的,但已经有相当的灵活度了,在这个游戏里,我可以指定布景的大小和地雷的数量。这样一来游戏就可以从头再玩,你可以把地雷 数量设置很小而很快能看到游戏的结果,这样有趣多了。下面就是这个游戏:

欢迎使用苹果iOS

此时,我已经感觉到应该转向真正的图形游戏了。我感觉陷入了僵局。我根本不知道从哪里入手。我研究了一下SDL,这个东西超过了我的接受能力,我很快放弃了。因为我知道最终我想做iPhone应用程序,我请教了Matt Rix (Trainyard),他给了我一些很好的建议。他建议我从学C语言开始,然后学Objective-C,然后Cocos2d。今天说起这些我很快高兴,这三种语言我都学会了,虽然很基础。

在学习C和Obj-C时,我遇到的大量的挫折,我没有做出多少游戏。很多次,我真的怀疑是否能渡过难关、找到出路。很多东西当我第一次看到时愁得我挠掉了很多头发:结构体,数组,多维数组,属性,表现层,控制层,协议和代理,内存管理,还有很多。很多东西我目前仍然无法理解领会。但是我坚持继续下去,我对很多人都说:让自己进步的唯一方法就是不断的做游戏。我十分清楚,想成为钢琴家,练习时根本,所以,这也是我需要的(我就持续这样下去)。

欢迎使用Cocos2d

一旦我最终把iPhone应用的基本知识攻克下,我立即开始研究Cocos2d。我很紧张,也很兴奋。现在,我不知道自己是太挑剔还是太笨,我感觉 Cocos2d的文档写的不太好。所有的类,方法,属性都列出来了,但却很难让人读懂,它们解释的不太清楚。一个例子:每个”node“(Cocos2d 的主要元素)都有一个”(BOOL) isRunning“属性。看起来非常的简单,但它似乎能够表示任何意思。所有的文档对这个属性的解释都是:”标志这个node是否在运行。嗯,ok … 不用说,Cocos2d里面有很多东西我都十分的困惑。

尽管这些的不满,我还是非常喜欢Cocos2d。一旦掌握了一些基本知识,我就开始研究它如何能够容易的做出一个简单游戏,让它马上能跑起来。我已经知道了如何做音乐和声效,我还知道一些Photoshop,我就真的开始要让它输出一些很酷的结果了。起初我对Cocos2d很困惑,我从Ray Wenderlich的一些非常棒的教材开始学习。

我开发的各种暂且算是游戏的游戏

下面的是我的第一个Cocos2d游戏,它是我直接按照Ray的教材开发出来的(我在里面还加上了我的音乐和当一个敌人被消灭时的很傻的音效!):

接着,我仿制了一个Pong。这个游戏还可以多人参与!:

Pong之后,我受到了鼓舞,决定开发Tetris。这是个巨大的错误。我根本没有准备好。我遇到了各种让人懊恼的错误和问题,当我最终把框架搭起来后,我在微博上写了这样的话:“我很骄傲。我为我的Tetris仿品开发了一个真正复杂的类/子类系统。”Noel Llopis很快的告诉我,说我的决定十分的错误。我搜集了一些教材,试图好好的修改一下这个仿Tetris游戏,但太困难了。我决定放弃,但有一天我会打败你的,Tetris!

这次Tetris失败的尝试之后,我受Tilt to Live的启发做了一个游戏初始原型,我计划在这个游戏里,你需要去收集红点来获取积分,而不是像其它游戏里去避开它们。现在做的这个里面并没有加入真正的游戏里面会有的音乐:

学习了更多的Cocos2d之后,我突然来了灵感要做一个循环的褶皱纸样式的背景。于是把一张纸做出褶皱型,以循环方式填充背景。然后我在上面放了 一个小圆片,你可以用加速器让它在上面滚动。当我弄明白如何让这个小圆片滚动后,我为自己能做出这个东西很自豪,因为这牵涉的一些数学知识,我并没有用很 久的时间就把它能明白了(尽管只是一个很简单的几何问题)。背景很难看 —— 但很好用:

接着,当我看到了即将发布的游戏Bumpy Road的令人惊讶的海报后,我受启发,心想是否能够也做一个跟里面的高高低低的路面相似风格的游戏元素。很显然,我的做图水平很有限,你可以比较一下。

Bumpy Road:

我的版本:

这之后,我想在真正的动画上试试身手。以前从没有做过动画,先在Photoshop试试。人物的制作很乏味冗长。即使是画一条很傻很短的线条也很费 劲。但我还是完成了,我把他称作“狂欢者”。他能做的就是一遍遍的张开和闭上他的大嘴,每次都随机的发出一些哼哼声。你还可以在屏幕上移动他。背景闪动不 同的颜色。当你触碰屏幕时,他只能哼哼和张嘴:

然而,“狂欢者”有了一小队粉丝。这些粉丝的头像图标里包括Mario, Link, Samus,等等。事实上我把这个游戏发给了Touch Arcade的Jared(嘿,是他向我要的)。之后,让我大吃一惊和无比高兴的是,Retro DreamerCraig Sharpe创作了我的第二张正规的粉丝的艺术作品!下面就是Craig为“狂欢者”创作的杰作:

他的作品是如此的优秀,我甚至把它放入了我的下一个游戏里。但起初,我突发奇想,要做一个跳杆子的游戏。起初的出发点只是为了使用一个简单的游戏技 术测试一下视差背景的效果,但做下来就做成了这个游戏。最终的游戏有一个小屏幕,有记分功能,有重玩功能,有音乐、音效,各种跳跃高杆,有一个高度指示 器,甚至还有一个鸣谢页面!它是我的功能最全的一个游戏。我在游戏里画了一些非常丑陋的精灵,就像你下面看到的:

因为画的太差,我询问Michael Hussinger是否愿意为我做一些简单的修改,他同意了!他在二十分钟内就画出来一个让人惊叹的匹萨伙计。我估计花几个小时也画不出这么好的作品来。他还为游戏中的视差效果画了一个漂亮的山作为背景。下面的就是在他的帮助下游戏的样子,我加上了标题和鸣谢页:

游戏运行中!

我的下一个游戏受Trainyard的启发。我想看看是否能做出 一个地图,上面画些网格道路,卡车能跑在上面。看看,制作“狂欢者”有了很好的回报。所以我称这个为“狂欢大巴”。游戏的玩法就是点击地图上的一个地方就 设定一个聚会点(一个闪烁的,颜色变换的点,伴有音乐),然后图上会画出一条路,通向这个点,“狂欢者”会把他的“狂欢大巴”开到那里。不用说,这是一个 非常简单的游戏。但里面很酷的东西是,当他到达目标地点后,音乐声会变大,卡车会开始跳舞,Craig画的作品会出现在开车上面左右摇摆!

代码写的很乱,有很多问题。我让弟弟试玩了一下,他式了三次,什么都没干成,他总是每次都是在错误的时间点击到错误的地方,这样游戏根本就不能正常 玩下去。每次我都要从头开始玩这个游戏,因为我没有给它加入“重新开始”的功能。但我还是挺为这个Trainyard的复制品感到自豪的。Matt应该为 此感谢我。

我的下一个项目是要做一条蛇。我发现了这个如何用flash做出一条蛇的教程, 我只需要把它移植到iPhone上。这个教材让我明白了很多如何做这种游戏的内幕。之前,我计划让蛇每一帧移动一次,但在如何让蛇尾和蛇身保持一致的问题 上遇到了很多的麻烦。我本打算建一个数组存所有历史动作,蛇尾将按照这个数组里的信息做它的每个动作,但这样一来它动的太快,让人很不舒服。这个教程整个 颠倒了我的思维,我意识到蛇其实根本没有动。这种看起来在移动的视觉效果其实是简单的在帧上添加和移去一小段蛇身产生的。这样,当你捡起一 个苹果,所需要做的只是告诉程序不要删除任何片段。事实上我需要重新写这个程序,因为界面太难看了,控制的也不好。因为我是移植过来的,代码写的很乱。但 事实上作为一个基本的游戏来,它还是很不错的!

在完成这条蛇之后,我打算制作“狂欢大巴2”:“狂欢者”的周末狂欢。我把上一版升级了一些。我在里面加入了一些Trainyard里面的速度条, 一个车站,车可以从里面开车,一些声音特效(当他被碰着时会出现很大的汽车相撞的声音,而且会喊出“今天没有活动!”),程序也整理的更整洁了。但没多 久,程序又开始变乱,当我要纠正一个问题时,另外一个东西又出现了问题。最大的问题是当我把速度设成最大时,卡车会在路上某个点崩溃。这是因为更新调用的 太频繁,程序来不及在下一次调用前更新完。尽管我知道这个问题的原因,如想修复这个问题需要重做大量的东西。我想我需要升级到“狂欢大巴3”:最后的狂 欢。

我最近的目标是重做Doodle Jump。目前为止一切进展顺利。里面很多小平台,移动速度会约来越快,一个会跳的小人,一些其它物品(目前为止只有一个弹簧),自定义音乐和声效,以及完全从原作里拷贝的背景。目前为止我对做出的东西很高兴。我会继续往里面增加很多的东西。

结论

练习给人带来的进步是惊人的。每次当写出一个新程序,我都会遇到大量的无法预知的问题和bug。当遇到挫折时,我一般是将问题移到下一次升级时解决。这让我感觉自己就在走一个while循环: while (编程技术仍然很糟) {

  练习时间++;
  程序 /* 新程序 = [程序 程序类型:游戏];

  if (新程序.做的很好吗 == 是的 && 练习时间 >= 大量) {
      编程技术仍然很糟 = 否;

  }

}

我会一直这样制作下去,一转眼就到现在了,我几乎等不及想知道再6个月后会是什么样。请下次当我来述说如何给Casey’s Contraptions制作音乐(和一些声音)时,请记住一定来看看!

本文由“外刊IT评论”网(www.aqee.net)荣誉出品 [英文原文:My First Six Months of Programming: From Man-Rodent to Partyman ]

来源: [http://www.aqee.net/first-six-months/](http://www.aqee.net/first-six-months/)

用Python实现COM对象 能在VB等开发语言中调用 从而实现系统和Python扩展的独立开发 无

Posted on

用Python实现COM对象 能在VB等开发语言中调用 从而实现系统和Python扩展的独立开发 无缝集成

用Python实现COM对象 能在VB等开发语言中调用 从而实现系统和Python扩展的独立开发 无缝集成

作者:马维峰 李林 王晓蕊

    可以通过在组件式GIS开发中集成Python来提高开发效率和质量。Python可以在GIS系统开发中编写数据的导入导出、处理、分析等模块,以及应用 系统的业务逻辑层和科学研究中的空间分析、地学建模等模块。Python和组件式GIS可以通过PythonCOM实现的Python的COM接口来集 成,在VB等开发语言中调用使用Python开发的COM服务器组件,从而实现了GIS系统和Python扩展的独立开发,无缝集成……

1.1 初识Python 随着计算机和地理信息技术的飞速发展,GIS理论与应用的逐渐成熟,组件式技术已逐渐成为GIS 软件的主流,改变了传统集成式GIS 平台的工作模式,更适合用户进行二次开发以及与MIS、OA等其它系统的有机集成。代表性的组件式GIS有ERSI的ArcGIS和北京超图的 SuperMap Object。SuperMap Object是由北京超图公司和中科院地理与资源所开发研制的新一代大型组件式地理信息系统平台。

   由于大多数的脚本语言具有语法简单,易于学习,解释性、无需编译,易于部署和维护 等优点,与直接使用静态编程语言C、C++、VB等语言相比,使用动态脚本语言开发效率更高,开发和维护难度较低,作为系统扩展和快速开发语言具有一般静 态编程语言不具有的优势。通过脚本语言扩展或集成已有系统,在很多软件平台中得到了广泛应用。在ArcGIS、SuperMap Object等基于COM的组件式地理信息系统平台中,可以通过Python等支持COM的脚本语言对系统进行功能扩展,集成其他程序,编写数据的导入导 出、处理、分析等模块,特别是在应用系统开发的业务逻辑层(中间层)和科学研究中的空间分析、地学建模等方面更具优势。

Python是一门解释性、面向对象、动态语义特征的高层语言(Lutz,2001)。Python具有高层的内建数据结构,动态类型和动态绑定,丰 富的标准和第三方扩展库(包括科学计算、统计分析、可视化等模块),简单而易于阅读的语法,使其非常适合作快速应用开发来开发新系统、扩展已有系统,或作 为胶水语言来连接、集成已有部件。有关Python的信息和语法等请参考Python官方网站(http://www.python.org)。 本文将介绍如何应用Python来扩展SuperMap Object等组件式GIS的思路、方法和优势。 1.2**应用Python来扩展组件式GIS 1.2.1 Python的集成方式 在一般的编程语言中,集成或调用Python有以下几种方式:(1)在C或C++语言中,可以利用Python提供的接口,调用Python的特定功 能(Rossum,2003);(2)通过数据文件方式,通过操作系统的管道方式,直接调用Python执行环境和功能模块完成特定功能;(3)在 Windows环境下,可以使用PythonCOM扩展模块将Python编写的对象包装成COM对象,供支持COM的编程语言调用 (Hammond,2000)。其中(1)和(3)种方法为“无缝”集成,方法(2)为松散集成。 本文将通过PythonCOM扩展模块来完成与SuperMap Object相互调用。PythonCOM是由ActiveState公司开发的一个Python与COM、ASP集成的扩展模块,有关PythonCOM的信息请参考ActiveState公司网站(http://www.activestate.com)。以下将详细介绍如何创建一个可以被其他编程语言调用的Python模块,以及此模块如何与SuperMap Object交互完成特定的任务。 1.2.2**应用Python实现COM对象 使用Python实现一个COM对象首先需要定义一个Python类,实现需要的属性和方法;其次需要应用PythonCOM扩展,实现 ProgID、CLSID等属性,在注册表里注册这个Python类,使其成为一个可以被调用的COM对象。下面将通过一个简单的例子来说明这个过程。 我们来设计一个可以计算用户表达式的COM对象,以下是代码: /# SimpleEVAL.py – 表达式求解 class PythonEVAL: public_methods = [ 'MyEval' ] reg_progid = "PythonGISDemos.EVAL" /# Guid of this COM Searver reg_clsid = "{6288B5B7-870F-494E-A4F0-99868729804E}" def MyEval(self, source, myx): x = myx return eval(source) /# 自注册部分 if name=='__main': print "Registering COM server..." import win32com.server.register win32com.server.register.UseCommandLine(PythonEVAL)

以上的文件定义有3个特殊的属性字段,分别是: public_methods 可以被调用的方法列表,本代码只有一个方法“MyEval”。 reg_progid 对象的名称,用来调用这个对象时使用。 reg_clsid COM对象的CLSID,可以使用“pythoncom.CreateGuid()”这个方法来生成,也可以使用别的工具。 MyEval为我们定义的方法,参数为一个含“x”的表达式(字符串),和x的具体值,然后调用这个方法,返回计算后的值。后面的部分为自注册模块, 如果是在Python的交互环境下直接调用此模块,则运行这段代码。将这个文件保存在“Python23\Lib\site-packages”这个目录 下,首先运行一次,使其在注册表里注册这个COM组件。 这个对象可以应用在某些需要用户给出具体的表达式进行分析计算的模块中。在编写这个类的过程中,可以在Python的交互环境下边编写边测试,有助于验证算法和逻辑的正确性,保证开发效率和质量。 Python开发的COM对象也可以通过命令行进行注册和反注册。注册一个对象:“Python.exe YourServer.py”;反注册一个对象:“Python.exe YourServer.py –unregister”。需要说明的是这个对象一定要有以上程序的注册部分这一段代码。 PythonCOM还定义了除了“public_methods”以外其他一些特殊的属性字段,可以描述COM对象的其他特性。在代码中,还可以 通过“raise COMException("the error info")”这样的语句来进行错误处理。对于使用Python创建COM对象的其他细节问题请参考PythonCOM相关文档。 1.2.3**调用Python实现的COM对象** 调用Python编写的COM对象和调用其他COM对象方法一样,以下将通过VB代码来实例说明其调用方法。 在VB中新建一个工程,在缺省窗体上放置3个文本框和一个按钮,在Form_Load事件里编写对COM对象的初始化代码,在按钮点击事件里,编写COM对象调用的代码,在Form_Unload事件里,销毁这个对象。全部代码如下:

Public myServer As Object Private Sub Command1_Click() Text3.Text=myServer.MyEval(Text1.Text,Int(Text2.Text)) End Sub Private Sub Form_Load() Set myServer = CreateObject("PythonGISDemos.EVAL") End Sub Private Sub Form_Unload(Cancel As Integer) Set myServer = Nothing End Sub

整个代码和调用其他COM对象没有什么差别。以下是程序运行的界面,对x=2,表达式为“3/x – x/x”进行求解,结果是2。 http://www.gisforum.net/magazine/050415/images/picrdjs05.gif 图 1 VB中调用Python编写的COM对象的运行结果 我们可以把这段代码插入使用SuperMap Object等组件式GIS,开发语言为VB或其他语言的开发项目中需要用户给出具体的表达式进行分析计算的模块中。需要说明的是,对于参数传递,数据类 型,对象调用等使用COM开发需要注意的问题,在这里一样需要注意。另外有两个问题需要注意,第一,对于VB开发环境,VB是大小写不敏感的,而 Python是区分大小写的;第二是Unicode的问题,COM传递的字符串都是Unicode,在Python中处理使用之前要根据需要转换为Python的字符串。 1.3 应用实例 下面将使用Python来实现一个最小二乘拟合的模块。以下是代码:

/# LeastSq.py – 最小二乘拟合 from scipy import /* from scipy.optimize import leastsq

class PythonSq: public_methods = ['AddX','AddY','leastsq','GetP'] reg_progid = "PythonGISDemos.LeastSq" /# Guid of this COM Searver reg_clsid = "{6278B5B7-870F-494E-A4F0-92368724804E}" /#程序中需要拟合的X和Y的值 x=[] y=[] /#输入X和Y的值,由于一般语言没有对应的序列等数据结构,所以逐个输入 def AddX(self, xx): self.x.append(xx) def AddY(self, yy): self.y.append(yy) /#求解剩余变量 def residuals(self, p, y, x): a, b, c = p y = array(y) /#将序列转换为矩阵 x = array(x) err = y - (a/x/x + b/*x + c) return err /#求解参数 def leastsq(self): m_p = [1.0,1.0,1.0] self.p = leastsq(self.residuals,m_p,args=(self.y,self.x)) /#求返回值 def GetP(self, index): return self.p[0][index] /# 自注册部分(略)

程序代码的说明见注释。程序使用了SciPy扩展模块optimize模块(对于非线性方程,进行回归分析建议使用本方法,SciPy另外专门有线性代数模块(构建于ATLAS LAPACK和BLAS),可以进行线性代数运算,对于线性回归,具有更好的速度和稳定性。) (http://www.scipy.org),代码量很短,核心代码仅10余行,主要处理了输入和输出,定义了剩余变量的求解方式,主要的最小二次拟合 的代码仅1行,直接调用了optimize模块的leastsq方法。如果要改变拟合方程式,只需在residuals方法内修改“err = y - (a/x/x + b/*x + c)”括号内的部分即可。数据通过逐个输入方式输入,然后由Python读进其List中(如果需要传递大数据量的数据,笔者建议使用外部文件方式,由 VB等客户程序创建一个数据文件,然后将此文件路径传递给Python的COM组件,由Python读入(Python具有非常简单的文件读取和写入方式),构建为内部的List、Array或Matrix。) 。 在VB或其他语言中新建一个工程,测试此COM对象,以下为VB6下一个简单的测试代码:

Dim objSq As Object Set objSq = CreateObject("PythonGISDemos.LeastSq") Dim i As Integer '初始化回归值 For i = 0 To 100 objSq.AddX (CSng(i)) objSq.AddY (CSng(i) ^ 2 + Rnd()) Next '调用回归方法 objSq.leastsq MsgBox "A = " & objSq.GetP(0) MsgBox "B = " & objSq.GetP(1) MsgBox "C = " & objSq.GetP(2) Set objSq = Nothing

对于非线性方程,需要给出参数的初始值(leastsq方法内的m_p的值)。我们也可以使用前面举例介绍过的“eval”函数,编写一个可以对任意 表达式进行求解的最小二次拟合模块。对于代码的编写,可以首先在Python的交互式开发环境和IDE(Python自带的IDLE,PythonWin 等)下,边编写边测试,确定语法和逻辑没有错误后,即可完成模块,然后在其他环境下测试和使用,可以提高开发效率和质量。 1.4**结论** 通过PythonCOM接口,在基于COM的组件式GIS(例如SuperMap Object,ArcGIS)以及可以调用COM组件进行扩展的GIS工具的开发和扩展中集成Python,应用Python来开发部分功能组件具有以下优势: 1) 充分发挥Python动态语言解释性、语法简单、易于阅读、面向对象、动态语义、具有高层的内建数据结构等优势,可以提高开发效率和开发质量,缩短开发周期; 2) 基于COM的组件式开发保证了GIS系统的开发和Python扩展的开发的独立性,对于Python对象开发的组件,可以在任意时刻随意修改(包括编译打包后),不会影响GIS组件对其的调用; 3) 通过COM接口的调用和集成实现了Python和GIS工具的无缝集成; 4) Python优秀的科学计算、统计分析、可视化等扩展模块(SciPy,见http://www.scipy.org)可以方便的应用在GIS的数据处理、空间分析、地学模型分析等领域; 5) Python丰富的标准库和第三方扩展库可以在GIS与MIS、OA等应用性系统的集成开发中发挥积极的作用。

附:本文所列的代码都在Python和VB等环境下测试通过,测试软件环 境(Windows XP,VB 6.0,Python 2.3 + SciPy 0.3)。文中代码都略去了错误处理和捕获,在实际应用中,应该使用适当的错误处理机制。程序中有关Python、SciPy扩展模块、COM、VB等的 语法和使用方法,请参考其官方网站和相应文档。