2017-09-28 18 views
7

पायथन में, मेरे पास एक सजावट है जिसे किसी वास्तविक कार्य को छोड़ना पड़ता है यदि किसी फ़ंक्शन को स्थानीय रूप से परिभाषित किया जाता है जो इसे कॉल करता है।यह पता लगाने के लिए कि क्या फ़ंक्शन को स्थानीय रूप से परिभाषित किया गया है?

def fn1(): 
    # @my_decorator will be here 
    def fn2(): 
     pass 

    print(fn2) 
    return fn2 

x = fn1() 
print(x) 
print(x.__module__) 

यह इस प्रिंट:: मैं एक साधारण परीक्षण स्क्रिप्ट बनाया

<function fn1.<locals>.fn2 at 0x7fd61bdf3ae8> 
<function fn1.<locals>.fn2 at 0x7fd61bdf3ae8> 
__main__ 

के रूप में मैं देख रहा हूँ, अजगर देखता है कि समारोह (प्रिंट किया गया लेख में <locals>) एक स्थानीय अंतरिक्ष में परिभाषित किया गया है, लेकिन मैं यह नहीं देख सकता कि मैं उस डेटा का थोड़ा सा कैसे पा सकता हूं। मैं inspect मॉड्यूल के माध्यम से चला गया, और कुछ भी समान नहीं दिखता।

मैं भरोसा नहीं कर सकता कि समारोह ग्लोबल्स में है या नहीं।

मैं क्या उपयोग करूं? ,

'<locals>' in f.__qualname__ 

यह मेरे लिए भंगुर लगता है, हालांकि:

उत्तर

3

पहले, प्रत्यक्ष दृष्टिकोण की जांच करने के है अगर the CO_NESTED flag is set on the function's code object:

import inspect 

... 

def is_nested(func): 
    return func.__code__.co_flags & inspect.CO_NESTED 

def deco(func): 
    if is_nested(func): 
     # This is a nested function, return it unchanged 
     return func 
    ... otherwise, do your decoration here ... 

कि ने कहा, यदि आप जिस चीज की परवाह करते हैं, तो यह एक और तरीका है कि क्या आपने वास्तव में कुछ भी बंद कर दिया है या नहीं। एक समारोह जो संलग्न गुंजाइश से कुछ भी उपयोग नहीं करता है, घोंसला है, लेकिन बंद नहीं है, और वह भेद अक्सर महत्वपूर्ण होता है। उदाहरण के लिए:

def foo(x): 
    def bar(y): 
     pass 
    return bar 

नहीं एक बंद कर रही है क्योंकि barfoo कॉल के दायरे से कोई चर का उपयोग करता है। तक इसके विपरीत, भले ही यह एक कचरा संदर्भ है, इस enclosing दायरे से x का मूल्य पढ़कर बस एक बंद कर रही है:

def foo(x): 
    def baz(y): 
     pass 
    return bar 

आप __closure__ विशेषता परीक्षण द्वारा bar और baz के बीच का अंतर बता सकते हैं (None है यदि कोई नेस्टेड चर बंद नहीं किया गया है) या ऑब्जेक्ट की co_freevars विशेषता (जो नामों का एक गुच्छा बंद है, तो यह खाली है, तो यह बंद होने पर नहीं है, फिर भी यह बंद हो सकता है, हालांकि यह अभी भी बंद हो सकता है एक नेस्टेड फ़ंक्शन):

def is_closure(func): 
    return func.__closure__ is not None 
    # Or using documented names, since __closure__ isn't for some reason, 
    # co_freevars is a tuple of names captured from nested scope 
    return bool(func.__code__.co_freevars) 

    # Or on 3.3+, you even get a function to aid you: 
    return bool(inspect.getclosurevars(func).nonlocals) 
3

ठीक है, यहाँ एक hacky तरीका है।

एक और दृष्टिकोण Frame साथ खेलने के लिए है, लेकिन मुझे पसंद है कि और भी कम, मुझे लगता है:

In [1]: import inspect 

In [2]: def deco(f): 
    ...:  try: 
    ...:   frame = inspect.currentframe() 
    ...:   print(frame.f_back.f_locals is globals()) 
    ...:  finally: 
    ...:   del frame 
    ...:  return f 
    ...: 

In [3]: @deco 
    ...: def g(): pass 
    ...: 
True 

In [4]: def f(): 
    ...:  @deco 
    ...:  def g(): pass 
    ...: 

In [5]: f() 
False 
+0

मुझे लगता है कि यह एक वैध समाधान है। फ़ंक्शन के 'repr' को बनाने के लिए' __qualname__' भी उपयोग किया जाता है (कम से कम CPython में), इसमें कोई अन्य छुपा गुण नहीं है जो यह जांचता है। –

+0

@JimFasarakisHilliard हाँ, मैं 'inspect.currentframe() के साथ खेल रहा था। F_back.f_locals globals()' है, जो भी काम करता प्रतीत होता है, लेकिन मुझे यह भी * कम * पसंद है। –

संबंधित मुद्दे