Support multiple variables on LHS for varname.varname
EngHabu opened this issue · 10 comments
The code in here
Lines 243 to 266 in 6a1e8bd
assumes the Node is a function call. There are other AST Node types. For example, the code below:
class MyType(object):
def __eq__(self, other):
print(varname.nameof(self, caller=2))
return super().__eq__(other)
a = MyType()
print(a == 3)
Throws an exception because The Node in this case is a Compare Node
that doesn't have args
. It does, however, have n.left.id
to access the variable name we are calling __eq__()
on.
What are you expecting this to output:
print(varname.nameof(self, caller=2))
"self"
or "a"
?
"a"
.. I'm not positive about the value passed in to caller
(maybe 3?)
You should never use the caller
argument in a direct nameof
call, unless you are wrapping it in another function.
nameof
is supposed to get the variable name right at that stack.
To get the instance name, I suggest you do this:
import varname
class MyType(object):
def __init__(self, *args, **kwargs):
self.name = varname.varname()
def __eq__(self, other):
print(self.name)
return super().__eq__(other)
a = MyType()
print(a == 3)
My pattern is more like this:
import varname
class MyType(object):
def __init__(self, *args, **kwargs):
self.name = varname.varname(caller=3)
def __eq__(self, other):
print(f"name: {self.name}")
return super().__eq__(other)
def create_MyType():
return MyType(), MyType()
a, b = create_MyType()
print(a == 3)
print(b == 5)
Is there a way to get a
and b
here?
I think the use of caller
is sensible, the intended behaviour is meant to be similar to this:
import varname
class MyType(object):
def __len__(self):
print(varname.nameof(self, caller=2))
return 3
a = MyType()
len(a) # prints a
But the problem as originally stated is impossible. Consider this code:
class MyType(object):
def __eq__(self, other):
print("eq")
return True
a = MyType()
b = 3
a == b
b == a
There is no way to tell in a == b
which name is calling __eq__
.
@alexmojaki True. And __len__
now is actually a wrapper for nameof
(and of course you are doing something else inside).
@EngHabu
I see your point now. Now the problem is here:
Lines 411 to 424 in 6a1e8bd
instead of the fragment you attached initially. We only allow a Name
or Attribute
node currently.
Thinking about extending it into a List
/Tuple
of Name
or Attribute
nodes.
If the above is implemented, are you satisfied with this?
import varname
class MyType(object):
def __init__(self, name, *args, **kwargs):
self.name = name
def __eq__(self, other):
print(f"name: {self.name}")
return super().__eq__(other)
def create_MyType():
names = varname.varname()
types = [MyType(name) for name in names]
return types
a, b = create_MyType()
print(a == 3)
print(b == 5)
However, this will be a problem then:
a = create_MyType()
Since varname.varname
doesn't know it's going to be a single variable or multiple on the left-hand side.
So now it's a fight of giving it up or adding another argument in varname.varname
to explicitly require a single variable or multiple variables on LHS.
I like your idea @pwwang although I also agree with your assessment of the problem it raises.
The same thing can be done now with sorcery:
import sorcery
class MyType(object):
def __init__(self, name, *args, **kwargs):
self.name = name
def __eq__(self, other):
print(f"name: {self.name}")
return super().__eq__(other)
@sorcery.no_spells
def create_MyType():
names = sorcery.assigned_names()
types = [MyType(name) for name in names]
return types
a, b = create_MyType()
print(a == 3)
print(b == 5)
@EngHabu does that solve your problem?
Link to commit: 2694c21
How to use:
def func():
return varname(nvars=None)
a = func() # a == 'a'
a, b = func() # (a, b) == ('a', 'b')
[a, b] = func() # (a, b) == ('a', 'b')
# limit the number of variables on LHS
def func():
return varname(nvars=2)
a = func() # VarnameRetrievingError
a, b, c = func() # VarnameRetrievingError
a, b = func() # (a, b) == ('a', 'b')
In your case:
import varname
class MyType(object):
def __init__(self, name, *args, **kwargs):
self.name = name
def __eq__(self, other):
print(f"name: {self.name}")
return super().__eq__(other)
def create_MyType():
names = varname.varname(nvars=2)
types = [MyType(name) for name in names]
return types
a, b = create_MyType()
print(a == 3)
print(b == 5)
Closing this via v0.5.4
Now you can do:
import varname
class MyType(object):
def __init__(self, name, *args, **kwargs):
self.name = name
def __eq__(self, other):
print(f"name: {self.name}")
return super().__eq__(other)
def create_MyType():
names = varname.varname(multi_vars=True)
types = [MyType(name) for name in names]
return types
a, b = create_MyType()
print(a == 3)
print(b == 5)