Posted on 21-07-2014
Filed Under (技术) by waterlin

2.7.1 Python 里的 logging 有一个坑:

在进行 logging 配置之前,不要使用与 logging.info 输出任何日志,否则会引起日志输出的阻塞。

即不要在代码

logging.basicConfig(filename=logfilename,  level = logging.DEBUG,  format=logformat)

之前做任何日志输出操作,要做日志输出也需要在执行了这一段代码之后再做。

(0) Comments    Read More   
Posted on 07-12-2013
Filed Under (软件) by waterlin

Python 有一个自带的 IDE,用 Emacs 也可以写一写 Python 的脚本,不过,如果要写比较重量级一点的东西,还得用专业的 IDE 工具。这里推荐使用 Eric

  1. 安装 PyQt4

    推荐下载 Windows 下的安装文件直接安装,省得再用那个 SIP 编译源文件,请下载对应你的 Python 版本的 PyQt。

    安装了这个,就不用再单独安装 Qt 了,你所需要的一切都被 PyQt 安装好了。

    好像要安装到 Python 的安装目录下,不然死活找不到这个库的,无论你加到 Windows 的 Path 了没。

  2. 下载 Eric 并安装。

    下载解压后有个 install.py,运行 python install.py 即可。在 Windows 下,要求 QtCore4.dll 所在的文件夹包含在环境变量 PATH 中,不然安装时会提示找不到 QtCore4.dll。在 PyQt 安装时,默认会自动设定好环境变量。

    安装完毕后,直接双击 eric4.pyw 或 eric4.bat 运行 Eric4。不同之处在于后者会打开一个 DOS 黑窗口,不会影响性能,最多影响心情。

(0) Comments    Read More   
Posted on 23-05-2013
Filed Under (技术) by waterlin

Windows 有一个 CreateSymbolicLink 函数,可以用来创建软硬链接,不过对操作系统有硬性要求,桌面版本需要 Windows Vista 以上,服务器版本需要 Windows Server 2008 版本以上。

如果是在 Python 程序需要使用软链接或是硬链接来做一些文件操作,可以有两种方法:

1. 直接使用 Python Win32 API 模块:

import win32file

win32file.CreateSymbolicLink(fileSrc, fileTarget, 1)

2. 使用 ctypes 来实现 os.symlink 这个功能的抽象,以方便跨平台:

import os
from ctypes import *

__CSL = None
def symlink(source, link_name):
    '''symlink(source, link_name)
       Creates a symbolic link pointing to source named link_name'''
    global __CSL
    if __CSL is None:
        import ctypes
        csl = ctypes.windll.kernel32.CreateSymbolicLinkW
        csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32)
        csl.restype = ctypes.c_ubyte
        __CSL = csl
    flags = 0
    if source is not None and os.path.isdir(source):
        flags = 1
    if __CSL(link_name, source, flags) == 0:
        #raise ctypes.WinError()
        print "raise ctypes.WinError() Error"

os.symlink = symlink

定义了上述函数后,就可以直接在代码里用下面的函数来创建软、硬链接了:

if not os.path.islink(docpath):
    os.symlink(path, docpath)

3. 使用第三方右键菜单扩展工具:Link Shell Extension

如果是在 Windows XP 或是更低版本的操作系统里,是没有办法用上述两种办法,不过可以用 Link Shell Extension 来手动创建一个软、硬链接。

如果是在 Windows Vista 或是 Windows 7 上,可以使用 mklink 这个命令来创建链接。

(0) Comments    Read More   
Posted on 13-03-2013
Filed Under (技术) by waterlin

如果需要用 Python 调用 C/C++ 编写的第三方库(这些第三方库很可能就是你之前写出来的),只是需要一个脚本语言来粘合它们。这个时候,用 Python ctypes 可以很方便地实现调用。

StackOverflow 上的 Calling C/C++ from python 这个主题介绍了 ctypes 最简单的入门方法,概括如下:

  1. 如果是 C 函数库,则直接 load 这个库,然后调用即可;
  2. 如果是 C++ 函数库,则需要用 extern 关键字封装一个供 C 使用的函数,即把类隐藏到一些 C 风格的函数里,然后用 extern 标明这些函数,以方便外部调用。

这两种方法里,弄懂了 ctypes 调用 C++ 库的方法,就会用 ctypes 调用 C 函数库,对 C++ 库的基本方法如下。

例如,有一个 C++ 类 Foo:

#include <iostream>

class Foo{
    public:
        void bar(){
            std::cout << "Hello" << std::endl;
        }
};

再封装出下面 C 风格的接口函数:

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
}

把上面的代码编译成动态链接库:

g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

,然后再用 Python 写的代码来调用这个类,你可以把上面两个 C 接口函数写成 Python 类,或是直接调用:

from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')

class Foo(object):
    def __init__(self):
        self.obj = lib.Foo_new()

    def bar(self):
        lib.Foo_bar(self.obj)

,然后就可以在 Python 脚本里调用这个 Python 类了:

f = Foo()
f.bar() #and you will see "Hello" on the screen

在 Windows 下用 Python ctypes 的方法和上面一样,只是有下面两点需要注意一下:

  1. 在编写 Python 代码时,刚开始链接所需的动态链接库时,最好使用绝对路径来 load,以减少出错概率,加快调试速度

    在我按上面的方法编写好了上述代码时,一运行脚本,则提示如下错误信息:

    $ python Linkcpp.py
    Traceback (most recent call last):
      File "Linkcpp.py", line 2, in <module>
        lib = cdll.LoadLibrary('./LinkExample')
      File "C:\Python27\lib\ctypes\__init__.py", line 431, in LoadLibrary
        return self._dlltype(name)
      File "C:\Python27\lib\ctypes\__init__.py", line 353, in __init__
        self._handle = _dlopen(self._name, mode)
    WindowsError: [Error 126]
    

    这是因为我在代码里是使用了这样的代码来导入动态链接库:

    from ctypes import cdll
    lib = cdll.LoadLibrary('./LinkExample')
    

    如果把 ./LinkExample 这句换成 Windows 下的绝对路径 E:/PythonCode/LinkCpp/LinkExample,则没有错误提示了。当然,你直接把 ./LinkExample 换成 LinkExample 也可以找到该链接库。

    所以,刚开始的时候,使用绝对路径,以确保你不会纠结于能不能找到链接库之类的问题。

    在运行上述脚本的时候,出现 WindowsError: [Error 126] 的错误,无非就是两个原因

    • 你的 DLL 没有正确地被加载;
    • 你的 DLL 依赖的其它 DLL 没有被找到或是加载失败。

    另外,注意一下,Windows 下因为库分为 lib 和 dll 两个文件,所以可以只输入库的名称即可,比如说你要链接 LinkExample.dll 库,则可以在 ctypes 里只需要声明链接名为 LinkExample 库即可。

  2. 如果是 C++ 写的库,需要用上 extern 关键字,这个和一般的供 C 调用的 C++ 库头文件是一样的

    在 extern 声明的函数里,可以使用 C++ 里 C 没有的关键字,比如我的函数就是这样声明的:

    extern int linkExample(const int index, const char* name);
    

    上面代码可以从 Python 调用运行。

    extern 这个关键字在 C++ 里的用法比较复杂,在这里就是要声明一个供 C 使用的外部函数,而这个函数本身,却可以使用 C++ 的语法,包括 const 关键字等。

(0) Comments    Read More