سؤال

ال __debug__ يعد المتغير مفيدًا جزئيًا لأنه يؤثر على كل وحدة.إذا أردت إنشاء متغير آخر يعمل بنفس الطريقة، كيف أفعل ذلك؟

المتغير (لنكن أصليين ونسميه 'foo') لا يجب أن يكون عالميًا حقًا، بمعنى أنه إذا قمت بتغيير foo في وحدة واحدة، فسيتم تحديثه في الوحدات الأخرى.سأكون بخير إذا تمكنت من ضبط foo قبل استيراد الوحدات الأخرى وبعد ذلك سيرون نفس القيمة لها.

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

المحلول

أنا لا أؤيد هذا الحل بأي شكل أو شكل.ولكن إذا قمت بإضافة متغير إلى __builtin__ الوحدة النمطية، سيكون من الممكن الوصول إليها كما لو كانت عمومية من أي وحدة نمطية أخرى تتضمن __builtin__ -- وهي جميعها افتراضيًا.

a.py يحتوي على

print foo

يحتوي b.py على

import __builtin__
__builtin__.foo = 1
import a

والنتيجة هي طباعة "1".

يحرر: ال __builtin__ الوحدة متاحة كرمز محلي __builtins__ - هذا هو سبب التناقض بين اثنتين من هذه الإجابات.لاحظ ذلك أيضًا __builtin__ تمت إعادة تسميته إلى builtins في بيثون3.

نصائح أخرى

إذا كنت بحاجة إلى متغير عالمي عبر الوحدة النمطية، فربما يكفي مجرد متغير عالمي بسيط على مستوى الوحدة النمطية.

a.py:

var = 1

ب.py:

import a
print a.var
import c
print a.var

ج.py:

import a
a.var = 2

امتحان:

$ python b.py
# -> 1 2

مثال من العالم الحقيقي: ملف جانغو global_settings.py (على الرغم من أنه يتم استخدام إعدادات تطبيقات Django عن طريق استيراد ملف هدف django.conf.settings).

حدد وحدة نمطية (أطلق عليها اسم "globalbaz") وقم بتعريف المتغيرات بداخلها.يجب على جميع الوحدات التي تستخدم هذا "pseudoglobal" استيراد وحدة "globalbaz"، والإشارة إليها باستخدام "globalbaz.var_name"

يعمل هذا بغض النظر عن مكان التغيير، يمكنك تغيير المتغير قبل أو بعد الاستيراد.ستستخدم الوحدة المستوردة أحدث قيمة.(لقد اختبرت هذا في مثال لعبة)

للتوضيح، يبدو موقع globalbaz.py كما يلي:

var_name = "my_useful_string"

أعتقد أن هناك الكثير من الظروف التي يكون فيها الأمر منطقيًا ويبسط البرمجة للحصول على بعض العوالم المعروفة عبر عدة وحدات (مقترنة بإحكام).وبهذه الروح، أود أن أوضح قليلاً فكرة وجود وحدة من الوحدات العالمية التي يتم استيرادها بواسطة تلك الوحدات التي تحتاج إلى الرجوع إليها.

عندما يكون هناك وحدة واحدة فقط من هذا القبيل، أسميها "g".فيه، أقوم بتعيين قيم افتراضية لكل متغير أنوي التعامل معه على أنه عالمي.في كل وحدة تستخدم أيًا منها، لا أستخدم "from g import var"، لأن هذا يؤدي فقط إلى متغير محلي تتم تهيئته من g فقط في وقت الاستيراد.أقوم بإجراء معظم المراجع في النموذج G.Var ، و "G". بمثابة تذكير مستمر بأنني أتعامل مع متغير قد يكون متاحًا للوحدات النمطية الأخرى.

إذا كان سيتم استخدام قيمة هذا المتغير الشامل بشكل متكرر في بعض الوظائف في الوحدة النمطية، فيمكن لهذه الوظيفة إنشاء نسخة محلية:فار = g.var.ومع ذلك، من المهم أن ندرك أن التعيينات إلى var هي مهام محلية، ولا يمكن تحديث g.var العام دون الإشارة إلى g.var بشكل صريح في المهمة.

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

لا يزال من الممكن إسناد مهمة إلى g.x، على سبيل المثال، عندما لم يتم تعريف x بالفعل في g، ويمكن لوحدة مختلفة بعد ذلك الوصول إلى g.x.ومع ذلك، على الرغم من أن المترجم يسمح بذلك، إلا أن هذا النهج ليس شفافًا جدًا، وأنا أتجنبه.لا يزال هناك احتمال لإنشاء متغير جديد عن طريق الخطأ في g نتيجة لخطأ مطبعي في اسم المتغير للمهمة.في بعض الأحيان، يكون فحص dir(g) مفيدًا لاكتشاف أي أسماء مفاجئة قد تكون نشأت نتيجة لمثل هذا الحادث.

يمكنك تمرير العناصر العالمية لوحدة واحدة إلى وحدة أخرى:

في الوحدة أ:

import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var

في الوحدة ب:

def do_something_with_my_globals(glob): # glob is simply a dict.
    glob["my_var"]=3

عادة ما تكون المتغيرات العامة فكرة سيئة، ولكن يمكنك القيام بذلك عن طريق التعيين إلى __builtins__:

__builtins__.foo = 'something'
print foo

كما أن الوحدات نفسها هي متغيرات يمكنك الوصول إليها من أي وحدة.لذلك إذا قمت بتحديد وحدة تسمى my_globals.py:

# my_globals.py
foo = 'something'

ثم يمكنك استخدام ذلك من أي مكان أيضًا:

import my_globals
print my_globals.foo

استخدام الوحدات بدلاً من التعديل __builtins__ هي بشكل عام طريقة أنظف للقيام بالكرة العالمية من هذا النوع.

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

إنها ليست عادةً طريقة رائعة للقيام بالأشياء - نادرًا ما يكون استخدام الكرات العالمية - ولكن أعتقد أن هذه هي الطريقة الأنظف للقيام بذلك.

أردت نشر إجابة مفادها أن هناك حالة لن يتم العثور على المتغير فيها.

قد تؤدي الواردات الدورية إلى تعطيل سلوك الوحدة.

على سبيل المثال:

first.py

import second
var = 1

Second.py

import first
print(first.var)  # will throw an error because the order of execution happens before var gets declared.

main.py

import first

في هذا المثال، يجب أن يكون الأمر واضحًا، ولكن في قاعدة التعليمات البرمجية الكبيرة، يمكن أن يكون هذا مربكًا حقًا.

هذا يبدو وكأنه تعديل __builtin__ مساحة الاسم.للقيام بذلك:

import __builtin__
__builtin__.foo = 'some-value'

لا تستخدم __builtins__ مباشرة (لاحظ حرف "s" الإضافي) - يبدو أن هذا يمكن أن يكون قاموسًا أو وحدة نمطية.شكرًا لـ ΤΖΩΤΖΙΟΥ على الإشارة إلى ذلك، يمكن العثور على المزيد هنا.

الآن foo متاح للاستخدام في كل مكان.

لا أوصي بالقيام بذلك بشكل عام، لكن استخدامه متروك للمبرمج.

يجب أن يتم التعيين إليه كما هو مذكور أعلاه، فقط قم بالإعداد foo = 'some-other-value' سيتم تعيينه فقط في مساحة الاسم الحالية.

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

def builtin_find(f, x, d=None):
    for i in x:
        if f(i):
            return i
    return d

import __builtin__
__builtin__.find = builtin_find

بمجرد تشغيل هذا (على سبيل المثال، عن طريق الاستيراد بالقرب من نقطة الدخول الخاصة بك) يمكن لجميع الوحدات النمطية الخاصة بك استخدام find() كما لو أنها مدمجة بشكل واضح.

find(lambda i: i < 0, [1, 3, 0, -5, -10])  # Yields -5, the first negative.

ملحوظة: يمكنك القيام بذلك، بالطبع، باستخدام مرشح وخط آخر لاختبار الطول الصفري، أو مع تقليل نوع واحد من الخطوط الغريبة، لكنني شعرت دائمًا أنه غريب.

يمكنني تحقيق تعديل عبر الوحدة النمطية (أو متقلب) المتغيرات باستخدام القاموس:

# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60

# in myapp.mod1
from myapp import Timeouts

def wait_app_up(project_name, port):
    # wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
    # ...

# in myapp.test.test_mod1
from myapp import Timeouts

def test_wait_app_up_fail(self):
    timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
    Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
    with self.assertRaises(hlp.TimeoutException) as cm:
        wait_app_up(PROJECT_NAME, PROJECT_PORT)
    self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
    Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak

عند الانطلاق test_wait_app_up_fail, ، مدة المهلة الفعلية هي 3 ثواني.

تساءلت عما إذا كان من الممكن تجنب بعض عيوب استخدام المتغيرات العالمية (انظر على سبيل المثال. http://wiki.c2.com/?GlobalVariablesAreBad) باستخدام مساحة اسم فئة بدلاً من مساحة اسم عمومية/وحدة نمطية لتمرير قيم المتغيرات.يشير التعليمة البرمجية التالية إلى أن الطريقتين متطابقتان بشكل أساسي.هناك ميزة بسيطة في استخدام مساحات أسماء الفئات كما هو موضح أدناه.

تُظهر أجزاء التعليمات البرمجية التالية أيضًا أنه يمكن إنشاء السمات أو المتغيرات وحذفها ديناميكيًا في مساحات الأسماء العامة/الوحدة النمطية ومساحات أسماء الفئات.

wall.py

# Note no definition of global variables

class router:
    """ Empty class """

أُطلق على هذه الوحدة اسم "الجدار" نظرًا لأنها تُستخدم لارتداد المتغيرات.سيكون بمثابة مساحة لتعريف المتغيرات العامة والسمات على مستوى الفصل للفئة الفارغة "جهاز التوجيه" بشكل مؤقت.

source.py

import wall
def sourcefn():
    msg = 'Hello world!'
    wall.msg = msg
    wall.router.msg = msg

تستورد هذه الوحدة الجدار وتحدد وظيفة واحدة sourcefn الذي يحدد الرسالة ويرسلها من خلال آليتين مختلفتين، واحدة عبر النطاقات العالمية والأخرى عبر وظيفة جهاز التوجيه.لاحظ أن المتغيرات wall.msg و wall.router.message يتم تعريفها هنا لأول مرة في مساحات الأسماء الخاصة بها.

dest.py

import wall
def destfn():

    if hasattr(wall, 'msg'):
        print 'global: ' + wall.msg
        del wall.msg
    else:
        print 'global: ' + 'no message'

    if hasattr(wall.router, 'msg'):
        print 'router: ' + wall.router.msg
        del wall.router.msg
    else:
        print 'router: ' + 'no message'

تحدد هذه الوحدة وظيفة destfn والذي يستخدم آليتين مختلفتين لتلقي الرسائل المنبعثة من المصدر.فهو يسمح باحتمال عدم وجود المتغير "msg". destfn يقوم أيضًا بحذف المتغيرات بمجرد عرضها.

main.py

import source, dest

source.sourcefn()

dest.destfn() # variables deleted after this call
dest.destfn()

تستدعي هذه الوحدة الوظائف المحددة مسبقًا بالتسلسل.بعد المكالمة الأولى ل dest.destfn المتغيرات wall.msg و wall.router.msg لم تعد موجودة.

الإخراج من البرنامج هو :

عالمي:مرحبا بالعالم!
جهاز التوجيه:مرحبا بالعالم!
عالمي:لا توجد رسالة
جهاز التوجيه:لا توجد رسالة

تُظهر أجزاء التعليمات البرمجية أعلاه أن آليات الوحدة النمطية/العالمية وآليات متغير الفئة/الفئة متطابقة بشكل أساسي.

إذا كان سيتم مشاركة الكثير من المتغيرات، فيمكن إدارة تلوث مساحة الاسم إما باستخدام عدة وحدات من النوع الجداري، على سبيل المثال.الجدار 1، الجدار 2، إلخ.أو عن طريق تحديد عدة فئات من نوع جهاز التوجيه في ملف واحد.أما الأخير فهو أكثر ترتيبًا قليلًا، لذا ربما يمثل ميزة هامشية لاستخدام آلية متغير الفئة.

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