سؤال

إن وصول بايثون إلى متغيرات البيئة لا يعكس بدقة رؤية نظام التشغيل لبيئة العمليات.

لا يعمل os.getenv وos.environ كما هو متوقع في حالات معينة.

هل هناك طريقة للحصول على بيئة العملية الجارية بشكل صحيح؟


لتوضيح ما أعنيه، خذ البرنامجين المتكافئين تقريبًا (الأول بلغة C، والآخر بلغة python):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]){
    char *env;
    for(;;){
        env = getenv("SOME_VARIABLE");
        if(env)
            puts(env);
        sleep(5);
    }
}

import os
import time
while True:
    env = os.getenv("SOME_VARIABLE")
    if env is not None:
        print env
    time.sleep(5)

الآن، إذا قمنا بتشغيل برنامج C وألحقناه بعملية التشغيل باستخدام gdb وقمنا بتغيير البيئة تحت الغطاء عن طريق القيام بشيء مثل هذا:

(gdb) print setenv("SOME_VARIABLE", "my value", 1)
[Switching to Thread -1208600896 (LWP 16163)]
$1 = 0
(gdb) print (char *)getenv("SOME_VARIABLE")
$2 = 0x8293126 "my value"

ثم سيبدأ برنامج C المذكور أعلاه في إخراج "قيمتي" مرة واحدة كل 5 ثوانٍ.ومع ذلك، فإن برنامج بايثون المذكور أعلاه لن يفعل ذلك.

هل هناك طريقة لجعل برنامج بايثون يعمل مثل برنامج C في هذه الحالة؟

(نعم، أدرك أن هذا إجراء غامض جدًا ومن المحتمل أن يكون ضارًا عند تنفيذه في عملية قيد التشغيل)

أيضًا، أنا أستخدم حاليًا الإصدار 2.4 من python، وربما تم إصلاح ذلك في إصدار أحدث من python.

هل كانت مفيدة؟

المحلول

وهذا سؤال جيد جدا.

وتبين ان وحدة os تهيئة os.environ لقيمة posix .environ، التي تم تعيينها على مترجم بدء التشغيل. وبعبارة أخرى، لا يظهر مكتبة قياسية لتوفير الوصول إلى getenv وظيفة.

وهذا هو حال فإنه من المحتمل أن تكون آمنة للاستخدام ctypes على يونيكس. وبما انك ستكون استدعاء وظيفة LIBC فائقة القياسية.

نصائح أخرى

ويمكنك استخدام ctypes للقيام بذلك ببساطة جدا:

>>> from ctypes import CDLL, c_char_p
>>> getenv = CDLL("libc.so.6").getenv
>>> getenv.restype = c_char_p
>>> getenv("HOME")
'/home/glyph'

وهناك احتمال آخر هو استخدام فوسفات، أو بعض الدول الأخرى المصحح الثعبان بدلا من ذلك، وتغيير os.environ على مستوى بيثون، بدلا من المستوى C. هنا وصفة صغيرة نشرت لي أن يقطع على التوالي عملية الثعبان وتوفير إمكانية الوصول إلى وحدة تحكم الثعبان على تلقي إشارة. بدلا من ذلك، مجرد عصا pdb.set_trace () في مرحلة ما من التعليمات البرمجية التي تريد المقاطعة. في كلتا الحالتين، فقط تشغيل العبارة "import os; os.environ['SOME_VARIABLE']='my_value'"، ويجب أن يتم تحديثه بقدر ما تشعر بالقلق الثعبان.

ولست متأكدا إذا كان هذا وسيتم أيضا تحديث بيئة C مع ابق ضاغطا، لذلك إذا كان لديك وحدات C باستخدام getenv مباشرة قد تضطر إلى القيام ببعض المزيد من العمل للحفاظ على هذا متزامنا.

لا أعتقد أن العديد من البرامج ويتوقع أن يكون EVER بيئتهم تعديل خارجيا، وبالتالي تحميل نسخة من البيئة مرت عند بدء التشغيل هو ما يعادلها. لقد تعثر ببساطة على خيار التنفيذ.

إذا كنت ترى كل القيم مجموعة المعرضة للبدء التشغيل وputenv / ابق ضاغطا من داخل يعمل البرنامج، وأنا لا أعتقد أن هناك أي شيء لتكون مهتما. هناك طرق أنظف بكثير من تمرير المعلومات المحدثة إلى التشغيل التنفيذية.

النظر في كود مصدر بايثون (2.4.5):

  • تحصل الوحدات النمطية/posixmodule.c على البيئة في converterenviron() والتي يتم تشغيلها عند بدء التشغيل (انظر INITFUNC) وتقوم بتخزين البيئة في وحدة نمطية خاصة بالنظام الأساسي (nt أو os2 أو posix)

  • ينظر Lib/os.py إلى sys.builtin_module_names، ويستورد جميع الرموز من posix أو nt أو os2

لذا نعم، يتم تحديد ذلك عند بدء التشغيل.لن يكون os.environ مفيدًا هنا.

إذا كنت تريد حقًا القيام بذلك، فإن النهج الأكثر وضوحًا الذي يتبادر إلى ذهنك هو إنشاء وحدة python المخصصة الخاصة بك المستندة إلى لغة C، باستخدام getenv الذي يستدعي استدعاء النظام دائمًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top