4

如果您在 Python 中将大量值从 C 输出到 dict,有没有比以下更好(更快且更不容易出错)的方法:

    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
            );
4

4 回答 4

2

鉴于大多数值似乎来自,将它与对象spa中的其他松散属性一起封装并返回它可能是一个更好的主意。另外,.datetime.time

于 2010-12-12T21:45:58.883 回答
2

您可以使用宏:

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

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

此外,您可以删除尾随\0; 它没有任何目的。

于 2010-12-12T21:52:54.170 回答
2

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

基本上,您需要关于每个项目或键和值对的两条信息,这些信息将进入您正在构建的字典中。一件是放在Py_BuildValue()的格式字符串参数中的内容,第二件是它的键和关联值的来源。

您可以通过定义然后重新定义任务所需使用的宏来提取这两组信息中的每一个。对于您的示例,可以创建以下头文件。请注意如何定义两组不同宏中的一组,具体取决于它是否FORMATFIELDSd 时定义#include

// 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 接口工具可用(或者您可以编写自己的)来进一步帮助您创建这个单一的头文件,因为它的格式非常统一。

于 2010-12-13T05:41:16.010 回答
1

如果多个结构都需要这样做,那么我可能会编写一个小的 Python 脚本,通过从 .h 读取结构定义来生成此代码(例如,通过使用特殊注释标记您需要导出为 dicts 的结构和字段是什么) ... 所示案例中的最后三个字段需要手动添加到字典中。

我不会只为一个结构这样做,尤其是在结构稳定的情况下。

您是否考虑过使用 SIP 导出对象而不是 dicts?

于 2010-12-12T21:53:04.217 回答