2010-12-12 6 views
4

Wenn Sie eine Menge von Werten von C zu einem dict in Python ausgeben, gibt es einen besseren (schnelleren und weniger fehleranfällig) Weg, es zu tun, als:Python/C: Parsen Sie alle Werte gleichzeitig für die Rückkehr zu 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

Wenn Sie dieses Muster an mehreren Stellen haben, könnte ein [X-Makro] (http://en.wikipedia.org/wiki/C_preprocessor#X-Macros) hilfreich sein. – delnan

+3

Sie sollten '\ 0' nicht explizit so schreiben; String-Literale in C implizieren bereits einen Null-Terminator - wenn Sie '' foo ''schreiben, dann werden vier Bytes {' f ',' o ',' o ', 0} im statischen Speicher gespeichert. –

Antwort

2

Ich stimme @Martin v. Löwis über die Verwendung des C-Präprozessors und seiner Makrofunktionen zu, um zumindest einen Teil der Last der Einstellung und Wartung von etwas wie dem, was Sie tun, zu erleichtern. Wenn Sie diese Makros richtig definieren, können Sie alle definierenden Informationen an einer einzigen Stelle in einer einzigen Header-Datei speichern und vermeiden, sich zu wiederholen.

Grundsätzlich benötigen Sie zwei Informationen über jedes Element oder Schlüssel & Wertpaar, die in das Wörterbuch, das Sie erstellen, gehen sollen. Ein Stück ist das, was in Py_BuildValue() 's Formatzeichenfolgeargument gestellt wird, und das zweite ist die Quelle des Schlüssels und des zugehörigen Wertes dafür.

Sie können jeden dieser beiden Informationssätze extrahieren, indem Sie die für die Aufgabe benötigten Makros definieren und dann neu definieren. Für Ihr Beispiel könnte die folgende Header-Datei erstellt werden. Beachten Sie, wie einer von zwei verschiedenen Makrosätzen definiert wird, abhängig davon, ob FORMAT oder FIELDS zum Zeitpunkt definiert wurde, als es #include d war.

// 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 

Sobald Sie es einrichten, Ihre build_dict() Funktion, etwas zu werden ziemlich kurz und unabhängig von dem, was sein die tatsächlichen Inhalte des Wörterbuchs haben werden:

// 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" 
    ); 
} 

Während dies nicht der Fall ist vollständig automatisieren, könnte aber sehr helfen. Es sind wahrscheinlich zusätzliche Textverarbeitungs- oder C-Schnittstellen-Tools verfügbar (oder Sie könnten Ihre eigenen schreiben), um Ihnen bei der Erstellung dieser einzelnen Header-Datei weiter zu helfen, da sie in einem sehr einheitlichen Format vorliegt.

2

Da die meisten Werte scheinen kommen aus spa, ist es wahrscheinlich eine bessere Idee, es zusammen mit den anderen losen Eigenschaften within an object einzukapseln und nur das zurückgeben. Auch datetime.time.

2

können Sie Makros verwenden:

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

Dies wird Fehler in den String-Namen zu verhindern, und das Format-String. Fehler, nicht alle Felder aufzulisten, sind nicht einfach, AFAICT zu verhindern.

Sie können auch die nachfolgenden \0; es dient keinem Zweck.

1

Wenn das für mehrere Strukturen benötigt wird, dann würde ich wahrscheinlich ein kleines Python-Skript schreiben, um diesen Code zu generieren, indem ich die Strukturdefinition aus der .h (zB durch Markierung mit einem speziellen Kommentar was die Strukturen und Felder benötigen) um als dicts zu exportieren) ... die letzten drei Felder im gezeigten Fall müssten jedoch manuell zum Diktat hinzugefügt werden.

Ich würde das nicht nur für eine Struktur tun, besonders wenn die Struktur stabil ist.

Haben Sie erwogen, die Objekte anstelle von dicts zu exportieren, zum Beispiel mit SIP?