一、特征
- 核心特点:
- 使用函数/类调用从其内部检索变量的名称
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
, reticulate
withR
等。既不是 executing
也不是varname
100% 与这些环境一起工作。需要您自担风险使用它。
例如:
-
这不适用于
pytest
:a = 1 assert nameof(a) == 'a' # pytest manipulated the ast here # do this instead name_a = nameof(a) assert name_a == 'a'
网友评论