global variable python
باستخدام المتغيرات العالمية في وظيفة (12)
إذا قمت بإنشاء متغير عام في إحدى الوظائف ، فكيف يمكنني استخدام هذا المتغير في وظيفة أخرى؟
يمكننا إنشاء عالمي مع الوظيفة التالية:
def create_global_variable():
global global_variable # must declare it to be a global first
# modifications are thus reflected on the module's global scope
global_variable = 'Foo'
كتابة وظيفة لا تقوم بتشغيل كودها. لذلك نسميه الوظيفة create_global_variable
:
>>> create_global_variable()
باستخدام globals دون تعديل
يمكنك فقط استخدامه ، طالما أنك لا تتوقع تغيير الكائن الذي يشير إليه:
فمثلا،
def use_global_variable():
return global_variable + '!!!'
والآن يمكننا استخدام المتغير الشامل:
>>> use_global_variable()
'Foo!!!'
تعديل المتغير الشامل من داخل وظيفة
لتوجيه المتغير الشامل في كائن مختلف ، يجب عليك استخدام الكلمة الرئيسية العامة مرة أخرى:
def change_global_variable():
global global_variable
global_variable = 'Bar'
لاحظ أنه بعد كتابة هذه الوظيفة ، فإن الشفرة التي تقوم بتغييرها بالفعل لم تعمل بعد:
>>> use_global_variable()
'Foo!!!'
حتى بعد استدعاء الوظيفة:
>>> change_global_variable()
يمكننا أن نرى أن المتغير الشامل قد تغير. global_variable
اسم global_variable
الآن إلى 'Bar'
:
>>> use_global_variable()
'Bar!!!'
لاحظ أن "عالميًا" في بايثون ليس عالميًا حقًا - بل عالميًا فقط على مستوى الوحدة. لذلك فهي متاحة فقط للوظائف المكتوبة في الوحدات التي تكون عالمية. تتذكر الوظائف الوحدة التي كتبت بها ، لذلك عندما يتم تصديرها إلى وحدات أخرى ، فإنها لا تزال تبحث في الوحدة النمطية التي تم إنشاؤها فيها للعثور على المتغيرات العالمية.
المتغيرات المحلية بنفس الاسم
إذا أنشأت متغيرًا محليًا بالاسم نفسه ، فستطغى على متغير عام:
def use_local_with_same_name_as_global():
# bad name for a local variable, though.
global_variable = 'Baz'
return global_variable + '!!!'
>>> use_local_with_same_name_as_global()
'Baz!!!'
ولكن استخدام هذا المتغير المحلي الذي تم تجاهله لا يغير المتغير الشامل:
>>> use_global_variable()
'Bar!!!'
لاحظ أنه يجب تجنب استخدام المتغيرات المحلية بنفس الأسماء مثل globals إلا إذا كنت تعرف بالضبط ما تقوم به ولديك سبب وجيه جدًا للقيام بذلك. لم أواجه حتى الآن مثل هذا السبب.
كيف يمكنني إنشاء أو استخدام متغير عام في إحدى الوظائف؟
إذا قمت بإنشاء متغير عام في إحدى الوظائف ، فكيف يمكنني استخدام هذا المتغير الشامل في وظيفة أخرى؟ هل أحتاج إلى تخزين المتغير الشامل في متغير محلي للوظيفة التي تحتاج إلى الوصول إليها؟
أقوم بإضافة هذا لأنني لم أره في أي من الإجابات الأخرى وقد يكون مفيدًا لشخص ما يكافح بشيء مماثل. ترجع الدالة globals () إلى قاموس رمزي عالمي قابل للتغيير يمكنك من خلاله توفير بيانات "سحرية" لبقية الشفرة. فمثلا:
from pickle import load
def loaditem(name):
with open(r"C:\pickle\file\location"+"\{}.dat".format(name), "rb") as openfile:
globals()[name] = load(openfile)
return True
و
from pickle import dump
def dumpfile(name):
with open(name+".dat", "wb") as outfile:
dump(globals()[name], outfile)
return True
سيسمح لك فقط بتفريغ / تحميل المتغيرات من وإلى مساحة الاسم العامة. سوبر مريحة ، لا موس ، لا ضجة. متأكد من انها الثعبان 3 فقط.
إذا كنت أفهم موقفك بشكل صحيح ، فإن ما تراه هو نتيجة لكيفية معالجة بايثون لمساحات الأسماء المحلية (الوظيفة) والعامة (الوحدة النمطية).
لنفترض أنك حصلت على وحدة مثل هذه:
# sample.py
myGlobal = 5
def func1():
myGlobal = 42
def func2():
print myGlobal
func1()
func2()
قد تتوقع أن تقوم بطباعة 42 ، ولكن بدلاً من ذلك تقوم بطباعة 5. كما سبق ذكره ، إذا قمت بإضافة إعلان "عام" إلى func1()
، فحينئذٍ func2()
بطباعة 42.
def func1():
global myGlobal
myGlobal = 42
ما يحدث هنا هو أن بايثون تفترض أن أي اسم يتم تعيينه ، في أي مكان داخل الدالة ، يكون محليًا لهذه الوظيفة ما لم يتم إخباره بشكل صريح بخلاف ذلك. إذا كانت القراءة فقط من اسم ، وكان الاسم غير موجود محليًا ، فسيحاول البحث عن الاسم في أي نطاق يحتوي على نطاقات (على سبيل المثال ، النطاق العالمي للوحدة).
عند تعيين 42 إلى اسم myGlobal
، لذلك ، تقوم Python بإنشاء متغير محلي يظلل المتغير الشامل للاسم نفسه. يخرج المحلي من نطاق وهو garbage-collected عند إرجاع func1()
؛ في هذه الأثناء ، لا يمكن لـ func2()
مشاهدة أي شيء آخر غير الاسم العام (غير المعدل). لاحظ أن قرار مساحة الاسم هذا يحدث في وقت التحويل البرمجي ، وليس في وقت التشغيل - إذا كنت تقرأ قيمة myGlobal
داخل func1()
قبل تعيينها ، فستحصل على UnboundLocalError
، لأن Python قررت بالفعل أنه يجب أن تكون متغير محلي ولكن لم يتم ربط أي قيمة به حتى الآن. ولكن باستخدام العبارة " global
" ، تخبر بايثون أنه يجب أن تبحث في مكان آخر عن الاسم بدلاً من تعيينه محليًا.
(أعتقد أن هذا السلوك نشأ إلى حد كبير من خلال تحسين مساحات الأسماء المحلية - بدون هذا السلوك ، ستحتاج VM الخاصة بـ Python إلى إجراء ثلاثة عمليات بحث عن الأسماء على الأقل في كل مرة يتم فيها تعيين اسم جديد داخل دالة (للتأكد من أن الاسم لم يكن موجودًا) توجد بالفعل على مستوى الوحدة النمطية / مدمج) ، والتي من شأنها أن تبطئ بشكل كبير عملية شائعة جدا.)
إذا كنت تريد الإشارة إلى متغير عام في إحدى الدالات ، فيمكنك استخدام الكلمة الأساسية العمومية لتوضيح المتغيرات التي تكون عالمية. لا يتعين عليك استخدامه في جميع الحالات (كما يدعي شخص ما هنا بشكل غير صحيح) - إذا كان الاسم المشار إليه في تعبير لا يمكن العثور عليه في النطاق المحلي أو النطاقات في الوظائف التي تم تعريف هذه الوظيفة فيها ، فإنه يتم البحث عنه من بين المتغيرات.
ومع ذلك ، إذا قمت بتعيين متغير جديد لم يتم التصريح به كمتغير عالمي في الدالة ، فيتم الإعلان عنه ضمنيًا على أنه محلي ، ويمكن أن يطغى على أي متغير حالي موجود بالاسم نفسه.
أيضا ، المتغيرات العالمية مفيدة ، على عكس بعض المتعصبين OOP الذين يدعون غير ذلك - وخاصة بالنسبة للنصوص الأصغر ، حيث OOP هو مبالغة.
بالإضافة إلى الإجابات الموجودة بالفعل وجعل هذا أكثر إرباكًا:
في بايثون ، تكون المتغيرات التي يشار إليها فقط داخل الدالة شاملة بشكل ضمني . إذا تم تعيين متغير قيمة جديدة في أي مكان داخل جسم الدالة ، فمن المفترض أن تكون محلية . إذا تم تعيين قيمة جديدة داخل المتغير من أي وقت مضى داخل الدالة ، فسيكون المتغير ضمنيًا محليًا ، وستحتاج إلى الإعلان عنه صراحة باعتباره "عالميًا".
على الرغم من أن ذلك يثير بعض الدهشة في البداية ، إلا أن النظر في لحظة ما يفسر ذلك. من ناحية ، فإن المطالبة العالمية للمتغيرات المخصصة توفر حاجزًا ضد الآثار الجانبية غير المقصودة. من ناحية أخرى ، إذا كانت عالمية مطلوبة لكل المراجع العالمية ، فستستخدم عالميًا طوال الوقت. سيتعين عليك أن تعلن عالميًا عن كل مرجع إلى وظيفة مضمنة أو إلى أحد مكونات الوحدة المستوردة. هذه الفوضى سوف تهزم فائدة الإعلان العالمي لتحديد الآثار الجانبية.
المصدر: ما هي قواعد المتغيرات المحلية والعالمية في بايثون؟ .
بعد المتابعة وكإضافة ، استخدم ملفًا لاحتواء جميع المتغيرات العامة التي تم الإعلان عنها محليًا ثم "استيراد كـ":
الملف initval.py
Stocksin = 300
Prices = []
ملف getstocks.py
import initval as iv
Def getmystocks ():
iv.Stocksin = getstockcount ()
Def getmycharts ():
For ic in range (0,iv.Stocksin):
.....
تستخدم بايثون مجرّدًا بسيطًا لتحديد النطاق الذي يجب أن يحمّل منه متغيرًا ، بين المحلي والعالمي. إذا ظهر اسم متغير على الجانب الأيسر من المهمة ، ولكن لم يتم الإعلان عنه عالميًا ، فمن المفترض أن يكون محليًا. إذا لم يظهر على الجانب الأيسر من المهمة ، فمن المفترض أن يكون عالميًا.
>>> import dis
>>> def foo():
... global bar
... baz = 5
... print bar
... print baz
... print quux
...
>>> dis.disassemble(foo.func_code)
3 0 LOAD_CONST 1 (5)
3 STORE_FAST 0 (baz)
4 6 LOAD_GLOBAL 0 (bar)
9 PRINT_ITEM
10 PRINT_NEWLINE
5 11 LOAD_FAST 0 (baz)
14 PRINT_ITEM
15 PRINT_NEWLINE
6 16 LOAD_GLOBAL 1 (quux)
19 PRINT_ITEM
20 PRINT_NEWLINE
21 LOAD_CONST 0 (None)
24 RETURN_VALUE
>>>
انظر كيف أن baz ، الذي يظهر على الجانب الأيسر من المهمة في foo()
، هو المتغير LOAD_FAST
الوحيد.
جرب هذا:
def x1():
global x
x = 6
def x2():
global x
x = x+1
print x
x = 5
x1()
x2() # output --> 7
قد ترغب في استكشاف فكرة namespaces . في بايثون ، module هي المكان الطبيعي للبيانات العالمية :
تحتوي كل وحدة على جدول الرموز الخاص بها ، والذي يتم استخدامه كجدول الرمز العمومي بكافة الوظائف المحددة في الوحدة. وهكذا ، يمكن لمؤلف وحدة نمطية استخدام المتغيرات العالمية في الوحدة النمطية دون القلق من المصادمات العرضية مع المتغيرات العالمية للمستخدم. من ناحية أخرى ، إذا كنت تعرف ما تفعله ، فيمكنك أن تلمس المتغيرات العامة للوحدة باستخدام نفس الترميز المستخدم للإشارة إلى وظائفها ،
modname.itemname
.
تم وصف استخدام محدد للوحدة النمطية في الوحدة النمطية هنا - how-do-i-share-global-variables-across-modules ، ومن أجل اكتمال مشاركة المحتويات هنا:
الطريقة الأساسية لمشاركة المعلومات عبر الوحدات النمطية ضمن برنامج واحد هي إنشاء وحدة تكوين خاصة (غالباً ما تسمى config أو cfg). ما عليك سوى استيراد وحدة التكوين في جميع وحدات تطبيقك ؛ تصبح الوحدة النمطية متوفرة كإسم عام. نظرًا لوجود مثيل واحد فقط لكل وحدة نمطية ، فإن أي تغييرات يتم إجراؤها على كائن الوحدة النمطية تنعكس في كل مكان. فمثلا:
الملف: config.py
x = 0 # Default value of the 'x' configuration setting
الملف: mod.py
import config
config.x = 1
الملف: main.py
import config
import mod
print config.x
كما يتبين أن الإجابة بسيطة دائما.
هنا نموذج وحدة صغيرة مع طريقة بسيطة لإظهارها في تعريف main
:
def five(enterAnumber,sumation):
global helper
helper = enterAnumber + sumation
def isTheNumber():
return helper
فيما يلي كيفية إظهاره في تعريف main
:
import TestPy
def main():
atest = TestPy
atest.five(5,8)
print(atest.isTheNumber())
if __name__ == '__main__':
main()
يعمل هذا الرمز البسيط تمامًا كما سيتم تنفيذه. اتمني ان يكون مفيدا.
مرجع مساحة اسم الفئة حيث تريد أن يظهر التغيير.
في هذا المثال ، يستخدم runner max من ملف التكوين. أرغب في الاختبار الخاص بي لتغيير قيمة الحد الأقصى عندما يستخدمه runner.
الرئيسية / config.py
max = 15000
الرئيسية / runner.py
from main import config
def check_threads():
return max < thread_count
اختبارات / runner_test.py
from main import runner # <----- 1. add file
from main.runner import check_threads
class RunnerTest(unittest):
def test_threads(self):
runner.max = 0 # <----- 2. set global
check_threads()
مع التنفيذ المتوازي ، يمكن للمتغيرات العالمية أن تؤدي إلى نتائج غير متوقعة إذا لم تفهم ما يحدث. فيما يلي مثال على استخدام متغير عام داخل المعالجة المتعددة. يمكننا أن نرى بوضوح أن كل عملية تعمل بنسختها الخاصة من المتغير:
import multiprocessing
import os
import random
import sys
import time
def worker(new_value):
old_value = get_value()
set_value(random.randint(1, 99))
print('pid=[{pid}] '
'old_value=[{old_value:2}] '
'new_value=[{new_value:2}] '
'get_value=[{get_value:2}]'.format(
pid=str(os.getpid()),
old_value=old_value,
new_value=new_value,
get_value=get_value()))
def get_value():
global global_variable
return global_variable
def set_value(new_value):
global global_variable
global_variable = new_value
global_variable = -1
print('before set_value(), get_value() = [%s]' % get_value())
set_value(new_value=-2)
print('after set_value(), get_value() = [%s]' % get_value())
processPool = multiprocessing.Pool(processes=5)
processPool.map(func=worker, iterable=range(15))
انتاج:
before set_value(), get_value() = [-1]
after set_value(), get_value() = [-2]
pid=[53970] old_value=[-2] new_value=[ 0] get_value=[23]
pid=[53971] old_value=[-2] new_value=[ 1] get_value=[42]
pid=[53970] old_value=[23] new_value=[ 4] get_value=[50]
pid=[53970] old_value=[50] new_value=[ 6] get_value=[14]
pid=[53971] old_value=[42] new_value=[ 5] get_value=[31]
pid=[53972] old_value=[-2] new_value=[ 2] get_value=[44]
pid=[53973] old_value=[-2] new_value=[ 3] get_value=[94]
pid=[53970] old_value=[14] new_value=[ 7] get_value=[21]
pid=[53971] old_value=[31] new_value=[ 8] get_value=[34]
pid=[53972] old_value=[44] new_value=[ 9] get_value=[59]
pid=[53973] old_value=[94] new_value=[10] get_value=[87]
pid=[53970] old_value=[21] new_value=[11] get_value=[21]
pid=[53971] old_value=[34] new_value=[12] get_value=[82]
pid=[53972] old_value=[59] new_value=[13] get_value=[ 4]
pid=[53973] old_value=[87] new_value=[14] get_value=[70]