বহিরাগত, তবে বৈশ্বিক, স্কোপ নয়, অজগরটিতে পরিবর্তনশীল পরিবর্তন করা সম্ভব?


107

নিম্নলিখিত কোড দেওয়া:

def A() :
    b = 1

    def B() :
        # I can access 'b' from here.
        print( b )
        # But can i modify 'b' here? 'global' and assignment will not work.

    B()
A()

B()ফাংশন ভেরিয়েবলের কোডের জন্য bবাইরের স্কোপ হয় তবে বৈশ্বিক সুযোগে নয়। ফাংশন bথেকে পরিবর্তনশীল পরিবর্তন করা সম্ভব B()? অবশ্যই আমি এখান থেকে এটি পড়তে পারি এবং print()কীভাবে এটি পরিবর্তন করব?


দুঃখিত, অবশ্যই 2.7 :)। অজগরটির জন্য 3 স্কোপিংয়ের নিয়ম পরিবর্তন করা হয়েছে।
grigoryvp

আপনি যতক্ষণ bপার্শ্ব পরিবর্তনযোগ্য। bবাহ্যিক ক্ষেত্রটি মাস্ক করার জন্য একটি অ্যাসাইনমেন্ট ।
জিমবি

4
এটি পাইথনের অন্যতম বিব্রতকরতা যা nonlocal২.x এ ফিরে যায়নি। এটি ক্লোজার সাপোর্টের একটি অন্তর্গত অংশ part
গ্লেন মেইনার্ড

উত্তর:


96

পাইথন 3.x এর nonlocalকীওয়ার্ড রয়েছে । আমি মনে করি এটি আপনার যা ইচ্ছা তাই করে তবে আমি নিশ্চিত না আপনি অজগর 2 বা 3 চালাচ্ছেন কিনা।

ননলোকাল স্টেটমেন্টটি তালিকাভুক্ত শনাক্তকারীদের নিকটতম এনকোলেসিং স্কোপটিতে পূর্বের আবদ্ধ ভেরিয়েবলগুলি উল্লেখ করে। এটি গুরুত্বপূর্ণ কারণ বাইন্ডিংয়ের জন্য পূর্বনির্ধারিত আচরণ হ'ল স্থানীয় নেমস্পেসটি অনুসন্ধান করা। স্টেটমেন্টটি এনক্যাপসুলেটেড কোডটিকে বৈশ্বিক (মডিউল) সুযোগ ছাড়াও স্থানীয় স্কোপের বাইরে ভেরিয়েবলগুলি রিইন্ড করতে দেয়।

পাইথন 2 এর জন্য, আমি সাধারণত কেবলমাত্র একটি পরিবর্তনীয় অবজেক্ট (তালিকার মতো বা ডিকের মতো) ব্যবহার করি এবং পুনরায় সাইন ইন করার পরিবর্তে মানটি পরিবর্তন করি।

উদাহরণ:

def foo():
    a = []
    def bar():
        a.append(1)
    bar()
    bar()
    print a

foo()

আউটপুট:

[1, 1]

16
এটি করার একটি দুর্দান্ত উপায় class nonlocal: passবাইরের সুযোগে। তারপরে nonlocal.xঅভ্যন্তরীণ সুযোগে নির্ধারিত হতে পারে।
কিন্ডেল করুন

1
এখন অবধি, আমার কাছে ইতিমধ্যে দুটি অজগর টিপস রয়েছে যা সহজ, তবে খুব সহায়ক: আপনার দ্বিতীয়টি হ'ল :) ধন্যবাদ @ জ্যানডল!
swdev

@ জ্যানডল এটি দুর্দান্ত হ্যাক - এটি পাইথন 3 সিনট্যাক্সের চেয়ে ন্যূনতম এবং একটি পরিবর্তনীয় বস্তুর কাছাকাছি যাওয়ার চেয়ে অনেক বেশি পঠনযোগ্য।
ডিমো 414

2
@ জিনডল খুব ঝরঝরে ধন্যবাদ গাদা :) সম্ভবত আলাদা নামের প্রয়োজন যদিও এটি সামনের সামঞ্জস্যতা ভঙ্গ করে। পাইথন 3 এটা একটি শব্দ দ্বন্দ্ব এবং একটি কারণ হবে SyntaxError। সম্ভবত NonLocal?
অ্যাডাম টেরি

বা, যেহেতু এটি প্রযুক্তিগতভাবে একটি শ্রেণি Nonlocal,? :-)
21: 21

19

আপনি একটি অস্থায়ী সুযোগ রাখা খালি শ্রেণি ব্যবহার করতে পারেন। এটি পরিবর্তনীয় তবে কিছুটা সুন্দর tier

def outer_fn():
   class FnScope:
     b = 5
     c = 6
   def inner_fn():
      FnScope.b += 1
      FnScope.c += FnScope.b
   inner_fn()
   inner_fn()
   inner_fn()

এটি নিম্নলিখিত ইন্টারেক্টিভ আউটপুট দেয়:

>>> outer_fn()
8 27
>>> fs = FnScope()
NameError: name 'FnScope' is not defined

এটি এমনই আলাদা যে এর ক্ষেত্রগুলি সহ শ্রেণীর কোনও অভ্যন্তরীণ ফাংশনে "দৃশ্যমান" তবে ভেরিয়েবলগুলি হয় না, যদি না আপনি "ননলোকাল" কীওয়ার্ডের সাথে বাইরের ভেরিয়েবলটি সংজ্ঞায়িত করেন।
সেলডোর

12

আমি পাইথনে কিছুটা নতুন, তবে আমি এ সম্পর্কে কিছুটা পড়েছি। আমি বিশ্বাস করি আপনি যে সেরাটি পেতে যাচ্ছেন তা জাভা ওয়ার্ক-এভারের অনুরূপ, যা আপনার বাহ্যিক ভেরিয়েবলটিকে তালিকায় মোড়ানোর জন্য।

def A():
   b = [1]
   def B():
      b[0] = 2
   B()
   print(b[0])

# The output is '2'

সম্পাদনা: আমার ধারণা, পাইথন 3 এর আগে সম্ভবত এটি সত্য ছিল L মনে nonlocalহচ্ছে আপনার উত্তর is


4

না আপনি পারবেন না, অন্তত এইভাবে।

কারণ "সেট অপারেশন" বর্তমান স্কোপটিতে একটি নতুন নাম তৈরি করবে, যা বাইরেরটিকে আবরণ করবে।


"কোনটি বাইরেরটিকে আচ্ছাদন করে" আপনার অর্থ কী? নেস্টেড ফাংশনে বি নামের সাথে কোনও বস্তুর সংজ্ঞায়িত করার সাথে এই ফাংশনের বাইরের
জায়গাতে

1
@eyquem যা হ'ল অ্যাসাইনমেন্ট স্টেটমেন্ট যেখানেই থাকুক না কেন, এটি পুরো বর্তমান স্কোপে নামটি প্রবর্তন করবে। যেমন প্রশ্নের নমুনা কোড, যদি এটি হয়: ডিফ সি (): মুদ্রণ (খ) বি = 2 "বি = ২" পুরো সি ফানক স্কোপে নাম খ পরিচয় করিয়ে দেবে, সুতরাং যখন মুদ্রণ (খ) হবে, এটি হবে স্থানীয় সি ফানক স্কোপটিতে বি পাওয়ার চেষ্টা করুন তবে বাইরেরটি নয়, স্থানীয় খ এখনও শুরু করা হয়নি, সুতরাং একটি ত্রুটি ঘটবে।
zchenah

1

যে কেউ এটির জন্য পরে আরও বেশি নিরাপদে খুঁজছেন তবে ভারী কাজটি হ'ল। প্যারামিটার হিসাবে ভেরিয়েবল পাস করার প্রয়োজন ছাড়াই।

def outer():
    a = [1]
    def inner(a=a):
        a[0] += 1
    inner()
    return a[0]

1

সংক্ষিপ্ত উত্তর যা কেবল স্বয়ংক্রিয়ভাবে কাজ করবে

এই নির্দিষ্ট সমস্যাটি সমাধানের জন্য আমি পাইথন লাইব্রেরি তৈরি করেছি। এটি অনিয়মের অধীনে প্রকাশিত হয়েছে সুতরাং এটি আপনার ব্যবহারের মতো ব্যবহার করুন। আপনি এটি দিয়ে ইনস্টল করতে পারেনpip install seapie বা হোম পৃষ্ঠাটি এখানে দেখতে পারেন https://github.com/hirsimaki-markus/SEAPIE

user@pc:home$ pip install seapie

from seapie import Seapie as seapie
def A():
    b = 1

    def B():
        seapie(1, "b=2")
        print(b)

    B()
A()

আউটপুট

2

যুক্তিগুলির নিম্নলিখিত অর্থ রয়েছে:

  • প্রথম যুক্তিটি কার্যকর করার সুযোগ। 0 এর অর্থ স্থানীয় হবে B(), 1 এর অর্থ পিতামাতা A()এবং 2 এর অর্থ দাদা-পিতা <module>ওরফে গ্লোবাল
  • দ্বিতীয় যুক্তি হ'ল একটি স্ট্রিং বা কোড অবজেক্ট যা আপনি প্রদত্ত সুযোগে কার্যকর করতে চান
  • আপনি আপনার প্রোগ্রামের অভ্যন্তরীণ ইন্টারেক্টিভ শেলের জন্য যুক্তি ছাড়াই এটি কল করতে পারেন

দীর্ঘ উত্তর

এটি আরও জটিল। সিপিথন এপিআই ব্যবহার করে কল স্ট্যাকের ফ্রেমগুলি সম্পাদনা করে সিপি কাজ করে। সিপিথন হ'ল দ্য ফ্যাক্টো স্ট্যান্ডার্ড তাই বেশিরভাগ লোককে এটি নিয়ে চিন্তা করতে হবে না।

আপনি সম্ভবত যে যাদু শব্দটি ব্যবহার করছেন তা যদি আপনি এটি পড়তে থাকেন তবে নিম্নলিখিতটি নিম্নলিখিত:

frame = sys._getframe(1)          # 1 stands for previous frame
parent_locals = frame.f_locals    # true dictionary of parent locals
parent_globals = frame.f_globals  # true dictionary of parent globals

exec(codeblock, parent_globals, parent_locals)

ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),ctypes.c_int(1))
# the magic value 1 stands for ability to introduce new variables. 0 for update-only

পরবর্তীগুলি আপডেটগুলি স্থানীয় ক্ষেত্রের মধ্যে যেতে বাধ্য করবে। স্থানীয় স্কোপগুলি তবে বিশ্বব্যাপী সুযোগের চেয়ে আলাদাভাবে অপ্টিমাইজ করা হয়েছে সুতরাং যখন নতুন কোনও বস্তু প্রবর্তন করতে কিছু সমস্যা হয় যখন আপনি সেগুলি কোনওভাবেই শুরু না করা হলে সরাসরি কল করার চেষ্টা করেন। গিথুব পৃষ্ঠা থেকে এই সমস্যাগুলি রোধ করার কয়েকটি উপায় অনুলিপি করব

  • Assingn, আমদানি এবং আপনার বস্তু আগেই সংজ্ঞায়িত
  • আপনার বস্তুগুলিতে আগেই স্থানধারককে Assingn করা হচ্ছে
  • প্রতীক টেবিল আপডেট করতে প্রধান প্রোগ্রামটিতে নিজেকে পুনরায় স্বাক্ষর করুন: x = স্থানীয় () ["x"]
  • অপ্টিমাইজেশন এড়ানোর জন্য সরাসরি কল করার পরিবর্তে প্রধান প্রোগ্রামে এক্সিকিউট () ব্যবহার করুন। এক্স ডু বলার পরিবর্তে: এক্সিকিউট ("এক্স")

আপনি যদি অনুভব করছেন যে ব্যবহারের exec()সাথে আপনি যেতে চান এমন কিছু নয় তবে আপনি আসল স্থানীয় অভিধানটি (স্থানীয়দের দ্বারা প্রত্যাবর্তিত নয়) আপডেট করে আচরণের অনুকরণ করতে পারেন । আমি https://faster-cpython.readthedocs.io/mutable.html থেকে একটি উদাহরণ কপি করব

import sys
import ctypes

def hack():
    # Get the frame object of the caller
    frame = sys._getframe(1)
    frame.f_locals['x'] = "hack!"
    # Force an update of locals array from locals dict
    ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),
                                          ctypes.c_int(0))

def func():
    x = 1
    hack()
    print(x)

func()

আউটপুট:

hack!

0

আমি মনে করি না আপনি এটি করতে চান। যে ক্রিয়াকলাপগুলি তাদের সংযুক্ত প্রসঙ্গে জিনিসগুলিকে পরিবর্তন করতে পারে তা বিপজ্জনক, কারণ সেই প্রসঙ্গটি ফাংশনটির অজান্তেই লিখিত হতে পারে।

আপনি একটি স্পষ্ট করে তুলতে পারেন বি কে একটি পাবলিক পদ্ধতি এবং সি দ্বারা একটি শ্রেণীর একটি ব্যক্তিগত পদ্ধতি (সম্ভবত সেরা উপায়); বা একটি পরিবর্তনীয় ধরণের যেমন একটি তালিকা ব্যবহার করে এবং এটি স্পষ্টভাবে সিটিতে প্রেরণ করে:

def A():
    x = [0]
    def B(var): 
        var[0] = 1
    B(x)
    print x

A()

2
এর ভিতরে নেস্টেড ফাংশনগুলি না জেনে আপনি কীভাবে কোনও ফাংশন লিখতে পারেন? নেস্টেড ফাংশন এবং ক্লোজারগুলি তারা যে ফাংশনটিতে আবদ্ধ রয়েছে তার অভ্যন্তরীণ অংশ
গ্লেন মেইনার্ড

আপনার নিজের মধ্যে আবদ্ধ ফাংশনগুলির ইন্টারফেস সম্পর্কে আপনার জানা দরকার, তবে তাদের ভিতরে কী ঘটে যায় সে সম্পর্কে আপনাকে জানতে হবে না। এছাড়াও, তারা কল করে যে ফাংশনগুলি ইত্যাদিতে কী ঘটে তাও আপনার কাছ থেকে আশা করা যায় না ! যদি কোনও ফাংশন একটি অ-গ্লোবাল বা অ-শ্রেণিবদ্ধের সংশোধন করে তবে এটি সাধারণত এটি তার ইন্টারফেসের মাধ্যমে স্পষ্ট করে তোলে, অর্থাত প্যারামিটার হিসাবে গ্রহণ করে take
সিডিশো বব

পাইথন আপনাকে অবশ্যই এত ভাল হতে বাধ্য করে না, তাই nonlocalমূলশব্দটি - তবে এটি অত্যন্ত সতর্কতার সাথে ব্যবহার করা আপনার পক্ষে।
সিডিশো বব

5
@ বোয়াই: ভাষা ক্লিঙ্কের কারণে বাদে আমি কখনও এই জাতীয় ক্লোজার ব্যবহার মোটেও বিপজ্জনক বলে খুঁজে পাইনি। স্থানীয়দের অস্থায়ী শ্রেণি এবং স্থানীয় ফাংশনগুলিকে ক্লাসের পদ্ধতি হিসাবে মনে করুন এবং এটি এর চেয়ে জটিল আর নয়। ওয়াইএমএমভি, আমার ধারণা।
গ্লেন মেইনার্ড

0

আপনি পারবেন, তবে আপনাকে বৈশ্বিক স্ট্যাটামেন্টটি ব্যবহার করতে হবে (বৈশ্বিক ভেরিয়েবলগুলি ব্যবহার করার সময় যথারীতি খুব ভাল সমাধান নয়, তবে এটি কার্যকর হয়):

def A():
    global b
    b = 1

    def B():
      global b
      print( b )
      b = 2

    B()
A()


4
গ্লোবাল ভেরিয়েবল ব্যবহার সম্পূর্ণ ভিন্ন।
গ্লেন মেইনার্ড 18

0

আমি জানি না যে কোনও ফাংশনের বৈশিষ্ট্য রয়েছে যা দেয় __dict__ এই বাহ্যিক স্থান ==================================================================================================================================================== পাইথন 3 এ।

তবে পাইথন 2-তে যতদূর আমি জানি, তেমন কোনও বৈশিষ্ট্য নেই।

সুতরাং আপনি যা চান তা করার একমাত্র সম্ভাবনা হ'ল:

1) অন্যদের দ্বারা যেমন বলা হয়েছে তেমন কোনও পরিবর্তনযোগ্য বস্তু ব্যবহার করে

2)

def A() :
    b = 1
    print 'b before B() ==', b

    def B() :
        b = 10
        print 'b ==', b
        return b

    b = B()
    print 'b after B() ==', b

A()

ফলাফল

b before B() == 1
b == 10
b after B() == 10

নোট

ক্যাড্রিক জুলিয়েনের সমাধানটির একটি অসুবিধা রয়েছে:

def A() :
    global b # N1
    b = 1
    print '   b in function B before executing C() :', b

    def B() :
        global b # N2
        print '     b in function B before assigning b = 2 :', b
        b = 2
        print '     b in function B after  assigning b = 2 :', b

    B()
    print '   b in function A , after execution of B()', b

b = 450
print 'global b , before execution of A() :', b
A()
print 'global b , after execution of A() :', b

ফলাফল

global b , before execution of A() : 450
   b in function B before executing B() : 1
     b in function B before assigning b = 2 : 1
     b in function B after  assigning b = 2 : 2
   b in function A , after execution of B() 2
global b , after execution of A() : 2

কার্যকর করার পরে গ্লোবাল বিA() সংশোধন করা হয়েছে এবং এটি শুভ্র হতে পারে না

গ্লোবাল নেমস্পেসে আইডেন্টিফায়ার বি সহ কোনও বস্তু থাকলেই কেবল এটি ঘটবে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.