استخدام المتغيرات العالمية في دالة
-
05-07-2019 - |
سؤال
كيف يمكنني إنشاء أو استخدام متغير عام في دالة؟
إذا قمت بإنشاء متغير عام في دالة واحدة، فكيف يمكنني استخدام هذا المتغير الشامل في دالة أخرى؟هل أحتاج إلى تخزين المتغير العام في متغير محلي للوظيفة التي تحتاج إلى الوصول إليها؟
المحلول
ويمكنك استخدام متغير عمومي في وظائف أخرى بإعلان أنها global
في كل وظيفة أن يسند إليه:
globvar = 0
def set_globvar_to_one():
global globvar # Needed to modify global copy of globvar
globvar = 1
def print_globvar():
print(globvar) # No need for global declaration to read value of globvar
set_globvar_to_one()
print_globvar() # Prints 1
وأتصور أن السبب في ذلك هو أنه، منذ المتغيرات العالمية خطيرة جدا، بيثون تريد أن تتأكد من أن تعرف حقا هذا ما كنت تلعب مع من صراحة تتطلب الكلمة global
.
وانظر أجوبة أخرى إذا كنت ترغب في مشاركة متغير عمومي عبر وحدات.
نصائح أخرى
إذا أنا فهم الوضع بشكل صحيح، ما ترونه هو نتيجة لكيفية معالجة بيثون المحلية (وظيفة) و (وحدة) بمساحات العالمية.
ويقول كنت قد حصلت على حدة من هذا القبيل:
# sample.py
myGlobal = 5
def func1():
myGlobal = 42
def func2():
print myGlobal
func1()
func2()
وقد تتوقع هذا لطباعة 42، ولكن بدلا من ذلك فإنه يطبع 5. وكما سبق ذكره، إذا قمت بإضافة "global
" إعلان لfunc1()
، ثم func2()
سيتم طباعة 42.
def func1():
global myGlobal
myGlobal = 42
ما الذي يحدث هنا هو أن بيثون يفترض أن أي الاسم الذي تم المخصصة لم>، في أي مكان داخل دالة، المحلي إلى أن وظيفة إلا إذا قال صراحة على خلاف ذلك. إذا كان فقط <م> قراءة م> من اسم، واسم غير موجود محليا، فإنه سيحاول للبحث عن اسم في أي نطاقات تحتوي على (على سبيل المثال نطاق عالمي الوحدة النمطية).
عند تعيين 42 إلى myGlobal
اسم، وبالتالي، بيثون يخلق متغير محلي أن الظلال المتغير العالمي الذي يحمل نفس الاسم. يذهب هذا المحلية خارج النطاق وغير التي تم جمعها من القمامة عندما يعود func1()
. وفي الوقت نفسه، يمكن func2()
لا ترى أي شيء آخر غير (معدلة) اسم عالمي. لاحظ أن هذا القرار مساحة يحدث في وقت الترجمة، وليس في وقت التشغيل - لو كنت لقراءة قيمة myGlobal
داخل func1()
قبل تعيين إليها، وكنت الحصول على UnboundLocalError
، لأن بيثون قررت بالفعل انها يجب ان تكون محلية متغير ولكنه لم يكن له أي قيمة المرتبطة به حتى الان. ولكن عن طريق استخدام 'global
"بيان، كنت اقول بيثون أنه ينبغي أن ننظر في أي مكان آخر لاسم بدلا من تعيين إليها محليا.
(وأعتقد أن هذا السلوك نشأت إلى حد كبير من خلال الاستغلال الأمثل للمساحات المحلية - دون هذا السلوك، ستحتاج VM بايثون لأداء ثلاثة على الأقل اسم عمليات البحث في كل مرة يتم تعيين اسم جديد إلى داخل دالة (للتأكد من أن اسم لم تكن بالفعل موجودة في وحدة / مستوى مدمج)، التي من شأنها أن يتباطأ بشكل كبير عملية شائعة جدا.)
قد ترغب في استكشاف فكرة مساحات الأسماء.في بايثون، وحدة هو المكان الطبيعي ل عالمي بيانات:
تحتوي كل وحدة على جدول رموز خاص بها، والذي يتم استخدامه كجدول رموز عام بواسطة جميع الوظائف المحددة في الوحدة.وبالتالي، يمكن لمؤلف الوحدة استخدام المتغيرات العامة في الوحدة دون القلق بشأن التعارضات العرضية مع المتغيرات العامة للمستخدم.من ناحية أخرى، إذا كنت تعرف ما تفعله، فيمكنك لمس المتغيرات العامة للوحدة النمطية بنفس الترميز المستخدم للإشارة إلى وظائفها،
modname.itemname
.
تم وصف الاستخدام المحدد لـ global-in-a-module هنا - كيف يمكنني مشاركة المتغيرات العالمية عبر الوحدات؟, ، وللاكتمال تتم مشاركة المحتويات هنا:
تتمثل الطريقة الأساسية لمشاركة المعلومات عبر الوحدات داخل برنامج واحد في إنشاء وحدة تكوين خاصة (غالبًا ما تسمى التكوين أو 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
وبيثون يستخدم الكشف عن مجريات الأمور بسيطة لتحديد أي مجال يجب أن تحميل متغير من بين المحلي والعالمي. إذا ظهر اسم المتغير على الجانب الأيسر من واجب، ولكن لم يتم التصريح العالمي، فمن المفترض أن تكون محلية. اذا لم تظهر على الجانب الأيسر من واجب، فمن المفترض أن تكون عالمية.
>>> 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
>>>
وانظر كيف الباز، والذي يظهر على الجانب الأيسر من واجب في foo()
، هو المتغير الوحيد LOAD_FAST
.
إذا كنت تريد الإشارة إلى متغير عام في دالة، فيمكنك استخدام التابع عالمي الكلمة الأساسية للإعلان عن المتغيرات العالمية.لا يتعين عليك استخدامه في جميع الحالات (كما يدعي شخص ما هنا بشكل غير صحيح) - إذا تعذر العثور على الاسم المشار إليه في التعبير في النطاق المحلي أو النطاقات في الوظائف التي تم تعريف هذه الوظيفة فيها، فسيتم البحث عنه بين النطاقات العامة المتغيرات.
ومع ذلك، إذا قمت بتعيين متغير جديد لم يتم التصريح عنه على أنه عالمي في الوظيفة، فسيتم التصريح عنه ضمنيًا على أنه محلي، ويمكن أن يطغى على أي متغير عالمي موجود بنفس الاسم.
كما أن المتغيرات العامة مفيدة، على عكس بعض المتعصبين لـ OOP الذين يدعون خلاف ذلك - خاصة بالنسبة للنصوص الصغيرة، حيث يكون OOP مبالغًا فيه.
بالإضافة إلى الإجابات الموجودة بالفعل ولجعل هذا الأمر أكثر إرباكًا:
في بايثون، المتغيرات التي يتم الرجوع إليها فقط داخل الدالة هي العالمية ضمنا.إذا تم تعيين متغير قيمة جديدة في أي مكان داخل جسم الوظيفة ، فمن المفترض أن يكون محلي.إذا كان المتغير يتم تعيين قيمة جديدة داخل الوظيفة ، المتغير هو محلي ضمنيا ، وتحتاج إلى إعلانه صراحة على أنه "عالمي".
على الرغم من أنه مفاجئ بعض الشيء في البداية ، إلا أن التفكير لحظة يشرح هذا.من ناحية ، فإن طلب العالمية للمتغيرات المعينة يوفر ملف منع ضد الآثار الجانبية غير المقصودة.من ناحية أخرى ، إذا كان عالميا مطلوب لجميع المراجع العالمية ، ستستخدم جميع Global الوقت.يجب أن تعلن أن كل إشارة إلى مضمنة على أنها عالمية أو إلى مكون من وحدة نمطية مستوردة.هذه الفوضى من شأنها أن دحر فائدة الإعلان العالمي في تحديد الآثار الجانبية.
إذا يمكنني إنشاء متغير عمومي في وظيفة واحدة، كيف يمكنني استخدام هذا المتغير في وظيفة أخرى؟
اقتباس فقرة>ونحن يمكن أن تخلق العالمية مع الدالة التالية:
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()
استخدام غلوبالس دون تعديل
ويمكنك فقط استخدامه، طالما أنك لا تتوقع تغيير أي كائن يشير إلى:
وعلى سبيل المثال،
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
يشير الآن إلى '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!!!'
ملحوظة أنه يجب تجنب استخدام المتغيرات المحلية مع نفس الأسماء غلوبالس إلا إذا كنت تعرف بالضبط ما تقومون به، ويكون لها سبب وجيه جدا للقيام بذلك. لم أصادف حتى الان هذا السبب.
مع التنفيذ المتوازي، يمكن أن تؤدي المتغيرات العامة إلى نتائج غير متوقعة إذا لم تفهم ما يحدث.فيما يلي مثال لاستخدام متغير عام ضمن المعالجة المتعددة.يمكننا أن نرى بوضوح أن كل عملية تعمل بنسختها الخاصة من المتغير:
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]
وكما تبين كان الجواب دائما بسيطة.
وهنا هو وحدة عينة صغيرة مع وسيلة بسيطة لاظهار انها في تعريف 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()
وهذا رمز بسيط يعمل تماما مثل ذلك، وأنه سيتم تنفيذ. وآمل أن يساعد.
ما تقوله هو لاستخدام أسلوب مثل هذا:
globvar = 5
def f():
var = globvar
print(var)
f() # Prints 5
ولكن أفضل طريقة هي استخدام متغير عمومي مثل هذا:
globavar = 5
def f():
global globvar
print(globvar)
f() #prints 5
وكلاهما يعطي نفس الإخراج.
وتحتاج إلى مرجع متغير عمومي في كل وظيفة تريد استخدامها.
وكما يلي:
var = "test"
def printGlobalText():
global var #wWe are telling to explicitly use the global version
var = "global from printGlobalText fun."
print "var from printGlobalText: " + var
def printLocalText():
#We are NOT telling to explicitly use the global version, so we are creating a local variable
var = "local version from printLocalText fun"
print "var from printLocalText: " + var
printGlobalText()
printLocalText()
"""
Output Result:
var from printGlobalText: global from printGlobalText fun.
var from printLocalText: local version from printLocalText
[Finished in 0.1s]
"""
وأنت لا فعلا تخزين عالمي متغير محلي، مجرد إنشاء مرجع المحلية لنفس الكائن الذي يشير مرجعية عالمية الأصلية ل. تذكر أن كل شيء تقريبا في بيثون هو اسم يشير إلى كائن، ويحصل على نسخ شيء في العملية المعتادة.
إذا لم يكن لديك لتحديد صراحة عندما كان معرفا للإشارة إلى العالمية معرفة مسبقا، ثم كنت قد ويفترض أن تحدد بشكل واضح عندما يكون المعرف هو متغير محلي جديد بدلا من ذلك (على سبيل المثال، مع شيء من هذا القبيل " فار "قيادة ينظر في جافا سكريبت). منذ المتغيرات المحلية هي أكثر شيوعا من المتغيرات العالمية في أي نظام خطير وغير تافهة، ونظام بايثون أكثر منطقية في معظم الحالات.
أنت <م> يمكن م> ديهم لغة التي حاولت تخمين، وذلك باستخدام متغير عمومي إذا كان موجودا أو إنشاء متغير محلي إذا لم يفعل ذلك. ومع ذلك، من شأنه أن يكون عرضة للخطأ جدا. على سبيل المثال، واستيراد وحدة أخرى يمكن أن يعرض عن غير قصد متغير عمومي بهذا الاسم، وتغيير سلوك البرنامج.
وجرب هذا:
def x1():
global x
x = 6
def x2():
global x
x = x+1
print x
x = 5
x1()
x2() # output --> 7
في حال كان لديك متغير محلي يحمل نفس الاسم، قد ترغب في استخدام في وظيفة globals()
.
globals()['your_global_var'] = 42
وبعد يوم وباعتبارها إضافة لاستخدام ملف لاحتواء كل المتغيرات العالمية أعلنت عن محليا ثم import as
:
وملف <م> initval.py م>:
Stocksin = 300
Prices = []
وملف <م> getstocks.py م>:
import initval as iv
def getmystocks():
iv.Stocksin = getstockcount()
def getmycharts():
for ic in range(iv.Stocksin):
والكتابة على عناصر واضحة من مجموعة العالمية لا يبدو بحاجة إلى إعلان عالمي، على الرغم من الكتابة إليها "بالجملة" لديها هذا الشرط:
import numpy as np
hostValue = 3.14159
hostArray = np.array([2., 3.])
hostMatrix = np.array([[1.0, 0.0],[ 0.0, 1.0]])
def func1():
global hostValue # mandatory, else local.
hostValue = 2.0
def func2():
global hostValue # mandatory, else UnboundLocalError.
hostValue += 1.0
def func3():
global hostArray # mandatory, else local.
hostArray = np.array([14., 15.])
def func4(): # no need for globals
hostArray[0] = 123.4
def func5(): # no need for globals
hostArray[1] += 1.0
def func6(): # no need for globals
hostMatrix[1][1] = 12.
def func7(): # no need for globals
hostMatrix[0][0] += 0.33
func1()
print "After func1(), hostValue = ", hostValue
func2()
print "After func2(), hostValue = ", hostValue
func3()
print "After func3(), hostArray = ", hostArray
func4()
print "After func4(), hostArray = ", hostArray
func5()
print "After func5(), hostArray = ", hostArray
func6()
print "After func6(), hostMatrix = \n", hostMatrix
func7()
print "After func7(), hostMatrix = \n", hostMatrix
قم بالإشارة إلى مساحة اسم الفئة حيث تريد أن يظهر التغيير.
في هذا المثال، يستخدم عداء الأعلى من ملف التكوينأريد أن يغير اختباري قيمة الأعلى عندما يستخدمه العداء.
الرئيسي/config.py
max = 15000
main/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()
وأنا مضيفا ان هذا لأنني لم أر ذلك في أي من الإجابات الأخرى، وأنه قد يكون من المفيد لشخص يعاني من شيء مماثل. و 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 فقط.