簡體   English   中英

返回Python中的范圍變量

[英]Return the enclosing scope variables in Python

特定

我有一個函數, scope ,可以在一個封閉的命名空間(即模塊函數)中聲明 感興趣的變量位於該函數的外部。

如何一般性地訪問在任何封閉名稱空間中聲明的變量/參數及其值?

用於捕獲函數變量( b )和參數( c )的示例偽代碼:

a = 1
def func(c=3)
    b = 2
    def scope():
        return ...
    return scope()

預期產量

func()
# {'c': 3, 'b': 2}

嘗試

我在模塊級別取得了一定的成功,例如a = 1

# module-level
a = 1
def scope():
    return {k: v for k, v in globals().items() if not k.startswith("_")}

scope()
# {'a': 1, ...}

我也可以從方法訪問類屬性,例如b = 2

# class-level
a = 1
class Klass:
    b = 2
    def scope(self):
        obj = self.__class__
        return obj.__dict__

Klass().scope()
# {'b': 2, ...}

我只能部分訪問封閉函數中的變量和參數:

# function-level
a = 1
def func(c=3):
    b = 2
    def scope():
        obj = func
        return obj.__code__.co_varnames
    return scope()

func()
# ('c', 'b', 'scope')

盡管__code__.co_varnames成功提供了封閉變量(不包括a ),但我也對這些值感興趣(例如{'c': 3, 'b': 2} )。

我做了許多未提及的嘗試,包括inspect函數,其他代碼對象方法, dir()和對象特殊方法。 我的首選是實現更通用和慣用的代碼,以檢測封閉的命名空間中的變量,盡管可以理解任何建議。

我也知道Python的習慣用法和這個問題的性質。 我仍然對它的可能性感到着迷,並且我感謝任何願意超越常規的人。

盡管python將為您提供實現此目的的方法,但您確實不希望這樣做。 函數/類/等不應將其內部信息公開給調用代碼,因為這會破壞抽象並使代碼易碎。 函數應該接受參數並返回輸出值,但是內部算法,尤其是變量名不應該公開。

這有點作弊,但是

def scope(outer=locals()):
    return outer

作品。 (之所以作弊,是因為默認參數是在定義時由定義代碼求值的,因此locals()在封閉范圍內運行,因此實際上並不是scope函數伸到封閉范圍內。)

請注意,在調用后修改相應范圍時,由locals()返回的目錄可能會更改,也可能不會更改。 如果要在Python實現之間(甚至在不同用例之間)保持一致的行為,請在默認參數或scope函數主體中進行深拷貝。

# module-level

a = 1

def scope(outer=locals()):
    return outer

e = 5
result = scope()
f = 6

public_result = {k: v for k, v in result.items() if not k.startswith('_')}
assert (
    # allowed:
    public_result == dict(a=1)
    or
    # C-Python 3.6 behavior:
    public_result == dict(a=1, scope=scope, e=5, result=result, f=6)
)
# class-level

a = 1


class Klass:
    b = 2

    @staticmethod
    def _scope(outer=locals()):  # Hidden from public result, because I have
        return outer             # no idea how to refer to it from the outside.

    d = 4


e = 5
result = Klass._scope()
f = 6

public_result = {k: v for k, v in result.items() if not k.startswith('_')}
assert (
    # allowed:
    public_result == dict(b=2)
    or
    # CPython 3.6 behavior:
    public_result == dict(b=2, d=4)  # would also contain `scope` if it wasn't hidden
)
# function-level

a = 1


def func(c=3):
    b = 2

    def scope(outer=locals()):
        return outer

    return scope(), scope

    d = 4


e = 5
result, scope_fu = func()
f = 6

assert (
    # C-Python 3.6 behaviour:
    result == dict(b=2, c=3)
    or
    # also allowed:
    result == dict(b=2, c=3, scope=scope_fu, d=4)
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM