美文网首页
Python获取变量名模块之varname

Python获取变量名模块之varname

作者: 羋学僧 | 来源:发表于2023-06-13 22:14 被阅读0次

一、特征

  • 核心特点:
    • 使用函数/类调用从其内部检索变量的名称varname
    • 直接检索变量名,使用nameof
    • 检测下一个直接属性名称,使用will
    • 使用获取传递给函数的参数名称/源argname
  • 其他辅助 API(基于核心功能构建):
    • 一个值包装器,用于存储分配给值的变量名称,使用Wrapper
    • 注册__varname__到函数/类的装饰器,使用register
    • debug打印变量及其名称和值的函数

二、安装

pip install -U varname

请注意,如果您使用python < 3.8,请安装varname < 0.11

三、用法

3.1、使用检索变量名称varname(...)

  • 从函数内部

    from varname import varname
    def function():
        return varname()
    
    func = function()  # func == 'func'
    

    当有中间帧时:

    def wrapped():
        return function()
    
    def function():
        # retrieve the variable name at the 2nd frame from this one
        return varname(frame=2)
    
    func = wrapped() # func == 'func'
    

    或用于ignore忽略包裹的框架:

    def wrapped():
        return function()
    
    def function():
        return varname(ignore=wrapped)
    
    func = wrapped() # func == 'func'
    

    默认情况下忽略来自标准库的调用:

    import asyncio
    
    async def function():
        return varname()
    
    func = asyncio.run(function()) # func == 'func'
    

    用于strict控制调用是否应该直接赋值给变量:

    def function(strict):
        return varname(strict=strict)
    
    func = function(True)     # OK, direct assignment, func == 'func'
    
    func = [function(True)]   # Not a direct assignment, raises ImproperUseError
    func = [function(False)]  # OK, func == ['func']
    
    func = function(False), function(False)   # OK, func = ('func', 'func')
    
  • 检索类实例的名称

    class Foo:
        def __init__(self):
            self.id = varname()
    
        def copy(self):
            # also able to fetch inside a method call
            copied = Foo() # copied.id == 'copied'
            copied.id = varname() # assign id to whatever variable name
            return copied
    
    foo = Foo()   # foo.id == 'foo'
    
    foo2 = foo.copy() # foo2.id == 'foo2'
    
  • 左侧有多个变量

    # since v0.5.4
    def func():
        return varname(multi_vars=True)
    
    a = func() # a == ('a',)
    a, b = func() # (a, b) == ('a', 'b')
    [a, b] = func() # (a, b) == ('a', 'b')
    
    # hierarchy is also possible
    a, (b, c) = func() # (a, b, c) == ('a', 'b', 'c')
    
  • 一些不寻常的使用

    def function(**kwargs):
        return varname(strict=False)
    
    func = func1 = function()  # func == func1 == 'func1'
    # if varname < 0.8: func == func1 == 'func'
    # a warning will be shown
    # since you may not want func to be 'func1'
    
    x = function(y = function())  # x == 'x'
    
    # get part of the name
    func_abc = function()[-3:]  # func_abc == 'abc'
    
    # function alias supported now
    function2 = function
    func = function2()  # func == 'func'
    
    a = lambda: 0
    a.b = function() # a.b == 'b'
    

3.2、注册__varname__到函数/类的装饰器方式

  • 注册__varname__到函数

    from varname.helpers import register
    
    @register
    def function():
        return __varname__
    
    func = function() # func == 'func'
    
    # arguments also allowed (frame, ignore and raise_exc)
    @register(frame=2)
    def function():
        return __varname__
    
    def wrapped():
        return function()
    
    func = wrapped() # func == 'func'
    
  • 注册__varname__为类属性

    @register
    class Foo:
        ...
    
    foo = Foo()
    # foo.__varname__ == 'foo'
    

3.3、直接使用获取变量名nameof

from varname import varname, nameof

a = 1
nameof(a) # 'a'

b = 2
nameof(a, b) # ('a', 'b')

def func():
    return varname() + '_suffix'

f = func() # f == 'f_suffix'
nameof(f)  # 'f'

# get full names of (chained) attribute calls
func.a = func
nameof(func.a, vars_only=False) # 'func.a'

func.a.b = 1
nameof(func.a.b, vars_only=False) # 'func.a.b'

3.4、检测下一个直接属性名称

from varname import will
class AwesomeClass:
    def __init__(self):
        self.will = None

    def permit(self):
        self.will = will(raise_exc=False)
        if self.will == 'do':
            # let self handle do
            return self
        raise AttributeError('Should do something with AwesomeClass object')

    def do(self):
        if self.will != 'do':
            raise AttributeError("You don't have permission to do")
        return 'I am doing!'

awesome = AwesomeClass()
awesome.do() # AttributeError: You don't have permission to do
awesome.permit() # AttributeError: Should do something with AwesomeClass object
awesome.permit().do() == 'I am doing!'

3.5、使用获取参数名称/来源argname

from varname import argname

def func(a, b=1):
    print(argname('a'))

x = y = z = 2
func(x) # prints: x


def func2(a, b=1):
    print(argname('a', 'b'))
func2(y, b=x) # prints: ('y', 'x')


# allow expressions
def func3(a, b=1):
    print(argname('a', 'b', vars_only=False))
func3(x+y, y+x) # prints: ('x+y', 'y+x')


# positional and keyword arguments
def func4(*args, **kwargs):
    print(argname('args[1]', 'kwargs[c]'))
func4(y, x, c=z) # prints: ('x', 'z')


# As of 0.9.0 (see: https://pwwang.github.io/python-varname/CHANGELOG/#v090)
# Can also fetch the source of the argument for
# __getattr__/__getitem__/__setattr/__setitem__/__add__/__lt__, etc.
class Foo:
    def __setattr__(self, name, value):
        print(argname("name", "value"))

Foo().a = 1 # prints: ("'a'", '1')

3.6、价值包装

from varname.helpers import Wrapper

foo = Wrapper(True)
# foo.name == 'foo'
# foo.value == True
bar = Wrapper(False)
# bar.name == 'bar'
# bar.value == False

def values_to_dict(*args):
    return {val.name: val.value for val in args}

mydict = values_to_dict(foo, bar)
# {'foo': True, 'bar': False}

3.6、调试与debug

from varname.helpers import debug

a = 'value'
b = ['val']
debug(a)
# "DEBUG: a='value'\n"
debug(b)
# "DEBUG: b=['val']\n"
debug(a, b)
# "DEBUG: a='value'\nDEBUG: b=['val']\n"
debug(a, b, merge=True)
# "DEBUG: a='value', b=['val']\n"
debug(a, repr=False, prefix='')
# 'a=value\n'
# also debug an expression
debug(a+a)
# "DEBUG: a+a='valuevalue'\n"
# If you want to disable it:
debug(a+a, vars_only=True) # ImproperUseError

四、可靠性和局限性

varname都是靠executing包来寻找节点。确保检测到的节点executing是正确的(请参阅)。

它部分适用于其他 AST 魔法适用的环境,包括 pytest, ipython, macropy, birdseye, reticulatewithR等。既不是 executing也不是varname100% 与这些环境一起工作。需要您自担风险使用它。

例如:

  • 这不适用于pytest

    a = 1
    assert nameof(a) == 'a' # pytest manipulated the ast here
    
    # do this instead
    name_a = nameof(a)
    assert name_a == 'a'
    

相关文章

网友评论

      本文标题:Python获取变量名模块之varname

      本文链接:https://www.haomeiwen.com/subject/xbhhydtx.html