python global - باستخدام المتغيرات العالمية في وظيفة




variable java (16)

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

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

أيضا ، المتغيرات العالمية مفيدة ، على عكس بعض المتعصبين OOP الذين يدعون غير ذلك - وخاصة بالنسبة للنصوص الأصغر ، حيث OOP هو مبالغة.

كيف يمكنني إنشاء أو استخدام متغير عام في إحدى الوظائف؟

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


بالإضافة إلى الإجابات الموجودة بالفعل وجعل هذا أكثر إرباكًا:

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

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

المصدر: ما هي قواعد المتغيرات المحلية والعالمية في بايثون؟ .


قد ترغب في استكشاف فكرة 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

في حال كان لديك متغير محلي بنفس الاسم ، قد ترغب في استخدام الدالة globals() .

globals()['your_global_var'] = 42

تحتاج إلى الرجوع إلى المتغير الشامل في كل وظيفة تريد استخدامها.

على النحو التالي:

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]
"""

مرجع مساحة اسم الفئة حيث تريد أن يظهر التغيير.

في هذا المثال ، يستخدم 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()

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

يمكننا إنشاء عالمي مع الوظيفة التالية:

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 إلا إذا كنت تعرف بالضبط ما تقوم به ولديك سبب وجيه جدًا للقيام بذلك. لم أواجه حتى الآن مثل هذا السبب.


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

>>> 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 الوحيد.


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

لنفترض أنك حصلت على وحدة مثل هذه:

# 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 إلى إجراء ثلاثة عمليات بحث عن الأسماء على الأقل في كل مرة يتم فيها تعيين اسم جديد داخل دالة (للتأكد من أن الاسم لم يكن موجودًا) توجد بالفعل على مستوى الوحدة النمطية / مدمج) ، والتي من شأنها أن تبطئ بشكل كبير عملية شائعة جدا.)


ما تقوله هو استخدام الطريقة مثل هذا:

globvar = 5

def f():
    var = globvar
    print(var)

f()  # Prints 5

لكن أفضل طريقة هي استخدام المتغير الشامل مثل:

globavar = 5
def f():
    global globvar
    print(globvar)
f()   #prints 5

كلاهما يعطي نفس الناتج.


كما يتبين أن الإجابة بسيطة دائما.

هنا نموذج وحدة صغيرة مع طريقة بسيطة لإظهارها في تعريف 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()

يعمل هذا الرمز البسيط تمامًا كما سيتم تنفيذه. اتمني ان يكون مفيدا.


جرب هذا:

def x1():
    global x
    x = 6

def x2():
    global x
    x = x+1
    print x

x = 5
x1()
x2()  # output --> 7

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

إذا لم تكن مضطرًا إلى التحديد الصريح عندما كان المُعرّف يشير إلى عالمي مُعرَّف مسبقًا ، فحينئذٍ يتعين عليك بشكل صريح التحديد عندما يكون المُعرِّف متغيرًا محليًا جديدًا بدلاً من ذلك (على سبيل المثال ، باستخدام أمر مثل الأمر "var" ينظر في جافا سكريبت). وبما أن المتغيرات المحلية أكثر شيوعًا من المتغيرات العالمية في أي نظام جدي وغير تافه ، فإن نظام بايثون أكثر منطقية في معظم الحالات.

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


مع التنفيذ المتوازي ، يمكن للمتغيرات العالمية أن تؤدي إلى نتائج غير متوقعة إذا لم تفهم ما يحدث. فيما يلي مثال على استخدام متغير عام داخل المعالجة المتعددة. يمكننا أن نرى بوضوح أن كل عملية تعمل بنسختها الخاصة من المتغير:

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]

بعد المتابعة وكإضافة ، استخدم ملفًا لاحتواء جميع المتغيرات العامة التي تم الإعلان عنها محليًا ثم "استيراد كـ":

الملف 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):

.....


يمكنك استخدام:

sorted(d.items(), key=lambda x: x[1])

سيؤدي ذلك إلى فرز القاموس حسب قيم كل إدخال داخل القاموس من الأصغر إلى الأكبر.





python global-variables scope