F**k Python

Author:zumikua Updated at:2013-08-03 17:51:12 UTC

最近在做ACM比赛的时候尝试用了一下python,整个就恶心到我了……正好今天看了不少ruby和python的对比文,现在在这把心中积蓄的吐槽一吐为快。 首先,不内置正则表达式,卧槽连php那种垃圾语言都特么可以直接用正则的好不好?然后,我特么引用了正则后,想进行一次匹配 ``` def funcfull(mobj): return '{0}{1:03d}{2:03d}'.format(int(mobj.group(1)),int(mobj.group(2)),int(mobj.group(3))) full = re.compile('(\d{1,3})\ million\ (\d{1,3})\ thousand\ (\d{1,3})',re.IGNORECASE) now_line = full.sub(funcfull,now_line) ``` 特么这是人干事?我特么就为了匹配一个正则我还得新建一个方法?别和我提那个lambda,只支持一个表达式要你干屌?而且没有ruby好用的`$1`之类的全局方法,还只能新建一个方法来获取匹配结果 。 知道ruby怎么解决这个问题么? `str.gsub!(/(\d{1,3})\ thousand\ (\d{1,3})/i){sprintf("%d%3d",$1,$2)}` 高下立现! 而且python这傻逼的字符串格式化也很奇葩,查文档勉强支持的类C格式化字符串还不推荐使用,换了一个这种换汤不换药的format,你特么有什么意义! 就连php做的都比你们好知道么 ``` $php = '大家好我是傻逼的php' echo "$php" ``` 而且,其实本来我的那个字符串变量的名字定义成了str,当然,我这是按照官方文档的示例定义的。 然后,str特么还是类型转换的方法!卧槽我就不强求你类似Ruby能有个`.to_s`了你特么正常点来个ToString(val)行么?而且你连官方文档的示例都用str做标识符是闹哪样啊! 其他一些小问题我就不说了……什么方法的参数必须要用括号括起来啊,if while后面都必须要有冒号啊之类的,就当我是从ruby转过来水土不服好了。 然后 ,python 竟然不支持 class 的 reopen。 你特么是个动态语言啊!动态语言啊!你特么连reopen都不支持不会被人耻笑么?我特么不想从网上用个开源的库想稍微修改修改还特么得改源码啊!你知道Ruby有多么方便么? ``` class Array def X2 self.each{|i| i *= 2} end end ``` 内部类ruby都敢这样玩啊!你丫怎么就这么怂啊!ruby的元编程能把你爆出翔啊!实例可以重定义方法啊!你简直不知道这特么有多爽啊!配合reopen可以不修改原始代码直接hack代码啊!这是你们 python 永远不懂的啊! 嘛,想到那说那,说的比较乱,而且没学过python,只是对着文档随便来了两发,如有说错, 还望打脸。

初探mRuby,C程序嵌入以及自定义扩展

Author:zumikua Updated at:2014-03-01 16:04:24 UTC

博客荒废好长一段时间了,总感觉再不写点什么我说不定都提不起劲给VPS续费了……

mRuby已经release了1.0.0版本,虽然无论是文档还是社区建设mRuby都还有很长的一段路要走,但是对我来说尝鲜已经是足够了。

既然你会翻到这里估计我也就不用再费口舌介绍什么是mRuby了,那么下面我们就直接进入正题好了。

编译

Linux

之前在linux上编译过一次,不过说起来linux上编译起来真的有难度么?连configure都不需要直接装上bison、automake和ruby然后在代码根目录直接make就好。

Windows

曾经试过在Windows上编译一个Ruby出来,不过因为种种原因作罢了,这次编译mRuby也算是补回这个遗憾。

  1. 去GNUWIN32下载bison、make以及mingw32
  2. 安装一个版本的ruby
  3. 在环境变量中添加bison、make、gcc(mingw32提供)所在的路径,具体方法自己google
  4. 在mRuby源码的根目录下make
  5. Done

编译好了以后在build/host/bin/下提供了mruby、mirb和mrbc,分别对应ruby、irb以及rbc

mruby和mirb不用多说,mrbc好像是编译rb程序用的,我没用过就不多说了。

嵌入

正如mRuby名字所揭示的那样,她是一门专门用于嵌入(Embedded)的轻量级语言,类似于Lua。既然如此我们就首先来测试一下将Ruby嵌入到C程序中去。

#include<stdio.h>
#include<stdlib.h>
#include<mruby.h>
#include<mruby/compile.h>

int main(){
  char ruby_code[] = "puts 'Hello World'";
  mrb_state \*mrb = mrb_open();
  mrb_load_string(mrb,ruby_code);
  return 0;
}

嗯……好像还真是比Ruby简单不少……顺带一提之前我曾经试着在windows下将Ruby嵌入到C程序中去,可是使用RubyInstaller提供的名字叫1.9.1的lib总是会在运行的时候报段错误……(Ruby版本1.9.3),当然在Linux下没有任何问题就是了。

顺带一提,请自行设置include文件的搜索位置,以及需要链接的lib(libmruby.a,位于build\host\lib下),在此仅提供Code::Blocks自动生成的编译命令

mingw32-gcc.exe -Wall  -g    -IF:\mruby\mruby-1.0.0\include -c F:\mruby\main.c -o obj\Debug\main.o
mingw32-g++.exe -LF:\mruby\mruby-1.0.0\build\host\lib -o bin\Debug\mruby.exe obj\Debug\main.o   -lmingw32 F:\mruby\mruby-1.0.0\build\host\lib\libmruby.a 

好像同时指定了lib的搜索位置以及lib文件的绝对路径,嘛,不要在意

扩充

在C程序里单独嵌入一个Ruby命令没什么意思,我们来为其扩充一些我们自己定义的内容。

#include<stdio.h>
#include<stdlib.h>
#include<mruby.h>
#include<mruby/compile.h>
mrb_value foo_add(mrb_state\* mrb,mrb_value self){
  int a,b;
  mrb_get_args(mrb,"ii",&a,&b);
  return mrb_fixnum_value(a+b);
}
int main(){
  char ruby_code[] = "p Foo.new.add(1,2)";
  mrb_state \*mrb = mrb_open();
  struct RClass\* foo_class;
  foo_class = mrb_define_class(mrb,"Foo",mrb->object_class);
  mrb_define_method(mrb,foo_class,"add",foo_add,MRB_ARGS_REQ(2));
  mrb_load_string(mrb,ruby_code);
  return 0;
}

这样,我们就添加了一个名为Foo的类以及其一个实例方法add

参考代码,我们可以了解一下mrb定义方法的一般方式,foo_add是作为方法的具体实现函数,其返回类型以及参数类型都是固定的。而ruby传给该方法的参数则需要通过mrb_get_args(mrb,args...)获取。其中args表示各个参数的类型。具体参考此表:

string  mruby type     C type                 note

    o:      Object         [mrb_value]
    C:      class/module   [mrb_value]
    S:      String         [mrb_value]
    A:      Array          [mrb_value]
    H:      Hash           [mrb_value]
    s:      String         [char\*,int]            Receive two arguments.
    z:      String         [char\*]                NUL terminated string.
    a:      Array          [mrb_value\*,mrb_int]   Receive two arguments.
    f:      Float          [mrb_float]
    i:      Integer        [mrb_int]
    b:      Boolean        [mrb_bool]
    n:      Symbol         [mrb_sym]
    &:      Block          [mrb_value]
    \*:      rest argument  [mrb_value\*,int]       Receive the rest of the arguments as an array.
    |:      optional                              Next argument of '|' and later are optional.

\*来源于src/class.c内部的注释

需要指出的是,所有的ruby变量都是mrb_value类型, foo_add 函数的self参数指代instance自己。而对于mrb_define_class_method定义的类方法等self指代的是该类(Class类的instance)本身。

至于mrb_define_class以及mrb_define_method及其参数意义就不用我说了吧?稍微懂点英语就可以看懂了。

还有ruby中每个方法必须要有一个返回值,所以即使你没有返回值也要return mrb_nil_value();,而且函数必须返回mrb_value。(我一开始就直接想都没想用了void作为返回类型……)

很明显,这种方法只适合少量的零散的定义,而对于大量的,更加结构化的工程这种方法也有其局限性,而我们又常常会想要在Ruby类中储存一些持久化数据,但这又会牵扯到Ruby的垃圾回收(GC)工作机理,这一切我们会在后面讲解。

下一讲:

《mRuby:mrbgems以及在Ruby对象中储存struct》

Main