Python/C:一次解析所有值以返回Python?

问题描述:

如果您在C输出了大量的值在Python的字典,有没有更好的(更快且不易出错)的方式来做到这一点比:Python/C:一次解析所有值以返回Python?

return Py_BuildValue("{s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:d,s:(i,i,i,i),s:(i,i,i,i),s:(i,i,i,i)}", 
      "jd\0",    spa.jd, //Julian day 
      "jc\0",    spa.jc, //Julian century 
      "jde\0",   spa.jde, //Julian ephemeris day 
      "jce\0",   spa.jce, //Julian ephemeris century 
      "jme\0",   spa.jme, //Julian ephemeris millennium 
      "l\0",    spa.l, //earth heliocentric longitude [degrees] 
      "b\0",    spa.b, //earth heliocentric latitude [degrees] 
      "r\0",    spa.r,  //earth radius vector [Astronomical Units, AU] 
      "theta\0",   spa.theta, //geocentric longitude [degrees] 
      "beta\0",   spa.beta, //geocentric latitude [degrees] 
      "x0\0",    spa.x0, //mean elongation (moon-sun) [degrees] 
      "x1\0",    spa.x1, //mean anomaly (sun) [degrees] 
      "x2\0",    spa.x2, //mean anomaly (moon) [degrees] 
      "x3\0",    spa.x3, //argument latitude (moon) [degrees] 
      "x4\0",    spa.x4, //ascending longitude (moon) [degrees] 
      "del_psi\0",  spa.del_psi, //nutation longitude [degrees] 
      "del_epsilon\0", spa.del_epsilon, //nutation obliquity [degrees] 
      "epsilon0\0",  spa.epsilon0, //ecliptic mean obliquity [arc seconds] 
      "epsilon\0",  spa.epsilon, //ecliptic true obliquity [degrees] 
      "del_tau\0",  spa.del_tau, //aberration correction [degrees] 
      "lamda\0",   spa.lamda, //apparent sun longitude [degrees] 
      "nu0\0",   spa.nu0, //Greenwich mean sidereal time [degrees] 
      "nu\0",    spa.nu, //Greenwich sidereal time [degrees] 
      "alpha\0",   spa.alpha, //geocentric sun right ascension [degrees] 
      "delta\0",   spa.delta, //geocentric sun declination [degrees] 
      "h\0",    spa.h, //observer hour angle [degrees] 
      "xi\0",    spa.xi, //sun equatorial horizontal parallax [degrees] 
      "del_alpha\0",  spa.del_alpha, //sun right ascension parallax [degrees] 
      "delta_prime\0", spa.delta_prime, //topocentric sun declination [degrees] 
      "alpha_prime\0", spa.alpha_prime, //topocentric sun right ascension [degrees] 
      "h_prime\0",  spa.h_prime, //topocentric local hour angle [degrees], 
      "h0_prime\0",  spa.h0_prime, 
      "delta_zero\0",  spa.delta_zero, 
      "e0\0",    spa.e0, //topocentric elevation angle (uncorrected) [degrees] 
      "del_e\0",   spa.del_e, //atmospheric refraction correction [degrees] 
      "e\0",    spa.e, //topocentric elevation angle (corrected) [degrees] 
      "eot\0",   spa.eot, //equation of time [minutes] 
      "srha\0",   spa.srha, //sunrise hour angle [degrees] 
      "ssha\0",   spa.ssha, //sunset hour angle [degrees] 
      "sta\0",   spa.sta, //sun transit altitude [degrees] 
      "zenith\0",   spa.zenith, //topocentric zenith angle [degrees] 
      "azimuth180\0",  spa.azimuth180, //topocentric azimuth angle (westward from south) [-180 to 180 degrees] 
      "azimuth\0",  spa.azimuth, //topocentric azimuth angle (eastward from north) [ 0 to 360 degrees] 
      "incidence\0",  spa.incidence, //surface incidence angle [degrees] 
      "_suntransit\0", spa.suntransit, //local sun transit time (or solar noon) [fractional hour] 
      "_sunrise\0",  spa.sunrise, //local sunrise time (+/- 30 seconds) [fractional hour] 
      "_sunset\0",  spa.sunset, //local sunset time (+/- 30 seconds) [fractional hour] 
      "sunrise\0",  sunrise_hour, sunrise_min, sunrise_sec, sunrise_microsec, 
      "sunset\0",   sunset_hour, sunset_min, sunset_sec, sunset_microsec, 
      "noon\0",   transit_hour, transit_min, transit_sec, transit_microsec 
      ); 
+0

如果你在几个地方有这种模式,[X宏](http://en.wikipedia.org/wiki/C_preprocessor#X-Macros)可能会有所帮助。 – delnan 2010-12-12 21:44:52

+3

你不需要像那样明确地写'\ 0'; C中的字符串文字已经意味着一个空终止符 - 如果你写了“”foo“',那么四个字节{'f','o','o',0}被存储在静态存储器中。 – 2010-12-12 21:53:24

我同意@Martin v。Löwis关于使用C预处理器及其宏功能来减轻至少一些设置和维护类似于您所做的事情的负担。如果您正确定义这些宏,您可以安排将所有定义信息放在单个头文件中的一个位置,并避免重复自己。

基本上,您需要两条关于每个项目或关键字&值的信息才能进入您正在构建的字典。一个是Py_BuildValue()的格式字符串参数,第二个是密钥的来源和关联值。

通过定义并重新定义任务所需的宏,可以提取这两组信息中的每一组信息。对于您的示例,可以创建以下头文件。请注意,如何定义两个不同宏集中的一个,具体取决于FORMAT还是FIELDS是在#included时定义的。

// builddict.h -- for defining Py_BuildValue() arguments 

// define apppropriate macros for current usage 
#ifdef FORMAT 
    #define SPA_FIELD_LAST(FIELD)   "s:d" 
    #define SPA_FIELD(FIELD)    SPA_FIELD_LAST(FIELD)", " 
    #define TIME_FIELD_LAST(NAME)   "s:(i,i,i,i)" 
    #define TIME_FIELD(NAME)    TIME_FIELD_LAST(NAME)", " 
    #define TIME_KEY_FIELD_LAST(KEY,NAME) "s:(i,i,i,i)" 
    #define TIME_KEY_FIELD(KEY,NAME)  TIME_KEY_FIELD_LAST(KEY,NAME)", " 
    #undef FORMAT 
#elif defined FIELDS 
    #define SPA_FIELD_LAST(FIELD)   #FIELD, spa.FIELD 
    #define SPA_FIELD(FIELD)    SPA_FIELD_LAST(FIELD), 
    #define TIME_FIELD_LAST(NAME)   #NAME, NAME##_hour, NAME##_min, NAME##_sec, NAME##_microsec 
    #define TIME_FIELD(NAME)    TIME_FIELD_LAST(NAME), 
    #define TIME_KEY_FIELD_LAST(KEY,NAME) #KEY, NAME##_hour, NAME##_min, NAME##_sec, NAME##_microsec 
    #define TIME_KEY_FIELD(KEY,NAME)  TIME_KEY_FIELD_LAST(KEY,NAME), 
    #undef FIELDS 
#else 
    #error neither FORMAT nor FIELDS usage macros are defined 
#endif 

SPA_FIELD(jd)    // Julian day 
SPA_FIELD(jc)    // Julian century 
SPA_FIELD(jde)    // Julian ephemeris day 
SPA_FIELD(jce)    // Julian ephemeris century 
SPA_FIELD(jme)    // Julian ephemeris millennium 
SPA_FIELD(l)    // earth heliocentric longitude [degrees] 
SPA_FIELD(b)    // earth heliocentric latitude [degrees] 
SPA_FIELD(r)    // earth radius vector [Astronomical Units) AU] 
SPA_FIELD(theta)   // geocentric longitude [degrees] 
SPA_FIELD(beta)    // geocentric latitude [degrees] 
SPA_FIELD(x0)    // mean elongation (moon-sun) [degrees] 
SPA_FIELD(x1)    // mean anomaly (sun) [degrees] 
SPA_FIELD(x2)    // mean anomaly (moon) [degrees] 
SPA_FIELD(x3)    // argument latitude (moon) [degrees] 
SPA_FIELD(x4)    // ascending longitude (moon) [degrees] 
SPA_FIELD(del_psi)   // nutation longitude [degrees] 
SPA_FIELD(del_epsilon)  // nutation obliquity [degrees] 
SPA_FIELD(epsilon0)   // ecliptic mean obliquity [arc seconds] 
SPA_FIELD(epsilon)   // ecliptic true obliquity [degrees] 
SPA_FIELD(del_tau)   // aberration correction [degrees] 
SPA_FIELD(lamda)   // apparent sun longitude [degrees] 
SPA_FIELD(nu0)    // Greenwich mean sidereal time [degrees] 
SPA_FIELD(nu)    // Greenwich sidereal time [degrees] 
SPA_FIELD(alpha)   // geocentric sun right ascension [degrees] 
SPA_FIELD(delta)   // geocentric sun declination [degrees] 
SPA_FIELD(h)    // observer hour angle [degrees] 
SPA_FIELD(xi)    // sun equatorial horizontal parallax [degrees] 
SPA_FIELD(del_alpha)  // sun right ascension parallax [degrees] 
SPA_FIELD(delta_prime)  // topocentric sun declination [degrees] 
SPA_FIELD(alpha_prime)  // topocentric sun right ascension [degrees] 
SPA_FIELD(h_prime)   // topocentric local hour angle [degrees]) 
SPA_FIELD(h0_prime) 
SPA_FIELD(delta_zero) 
SPA_FIELD(e0)    // topocentric elevation angle (uncorrected) [degrees] 
SPA_FIELD(del_e)   // atmospheric refraction correction [degrees] 
SPA_FIELD(e)    // topocentric elevation angle (corrected) [degrees] 
SPA_FIELD(eot)    // equation of time [minutes] 
SPA_FIELD(srha)    // sunrise hour angle [degrees] 
SPA_FIELD(ssha)    // sunset hour angle [degrees] 
SPA_FIELD(sta)    // sun transit altitude [degrees] 
SPA_FIELD(zenith)   // topocentric zenith angle [degrees] 
SPA_FIELD(azimuth180)  // topocentric azimuth angle (westward from south) [-180 to 180 degrees] 
SPA_FIELD(azimuth)   // topocentric azimuth angle (eastward from north) [ 0 to 360 degrees] 
SPA_FIELD(incidence)  // surface incidence angle [degrees] 
SPA_FIELD(suntransit)  // local sun transit time (or solar noon) [fractional hour] 
SPA_FIELD(sunrise)   // local sunrise time (+/- 30 seconds) [fractional hour] 
SPA_FIELD(sunset)   // local sunset time (+/- 30 seconds) [fractional hour] 
TIME_FIELD(sunrise) 
TIME_FIELD(sunset) 
TIME_KEY_FIELD_LAST(noon, transit) // must use a xxx_LAST macro on last one 

// clean up to prevent warnings about redefining macros 
#undef SPA_FIELD_LAST 
#undef SPA_FIELD 
#undef TIME_FIELD_LAST 
#undef TIME_FIELD 
#undef TIME_KEY_FIELD_LAST 
#undef TIME_KEY_FIELD 

一旦你拥有这一切成立,你build_dict()功能,成为东西相当短的,独立的什么字典的实际内容将会是:

// build format string using header 
char format_string[] = "{" 
    #define FORMAT 
    #include "builddict.h" 
"}"; 

// use header again to build list of fields 
PyObject* build_dict(SPA spa) 
{ 
    return Py_BuildValue(format_string, 
     #define FIELDS 
     #include "builddict.h" 
    ); 
} 

虽然这并不完全自动化这个过程,但是可以帮助很多。可能还有其他文本处理或C接口工具可用(或者您可以自己编写)以进一步帮助您创建此单个头文件,因为它具有非常统一的格式。

鉴于大部分值似乎来自spa,将其与其他松散属性within an object一起封装并返回即可。另外,datetime.time

您可以使用宏:

#define ADD_FIELD(F) PyDict_SetItemString(d, #F, spa.F) 
ADD_FIELD(jd); 
ADD_FIELD(jc); 
... 

这将防止字符串名称错误,格式字符串。 未列出所有字段的错误不容易阻止AFAICT。

此外,你可以删除尾随\0;它不起作用。

如果需要对几个结构,那么我可能会写一个小的Python脚本通过从.H(例如,通过一个特殊的标记注释阅读结构定义生成的代码是什么,你所需要的结构和字段导出为字典)......但是,所示情况下的最后三个字段需要手动添加到字典中。

我不会那样做,只为一个结构,特别是如果结构稳定。

您是否考虑导出对象而不是使用例如使用SIP的字典?