Hi Anatoly,
Haven't done any python in a loong time now, but I lurk
sometimes on the pypy list, and thought ok, I'll play with that,
and see if it's nay use to you.

I wrote techtonik.py (included at the end) and used it interactively
to show some features, first trying to approximate the interaction you gave
as an example (well, except the ns. prefix ;-)

I may have gone a little overboard, tracking re-assignments etc ;-)
HTH

On 07/15/2014 11:05 AM anatoly techtonik wrote:
Hi,

Is it possible at all to define a class in Python that
can read name of variable it is assigned to on init?

   >>> MyObject = SomeClass()
   >>> print(MyObject)
   'MyObject'

For this to work, SomeClass __init__ needs to know
what variable name is currently waiting to be
assigned. But at the time __init__ is executed,
MyObject is not entered global or local space yet.

I know that this is possible to do on AST level, but
AST is inaccessible when program is running, so
what is the corresponding structure to track that?
(links to source are appreciated)

1. Is it possible to do this in CPython and PyPy?
2. Is it possible to do this in generic way?
3. Is there any stack of assignments?
3.1. Is this stack accessible?

Thanks.

---
Python 2.7.3 (default, Jul  3 2012, 19:58:39)
[GCC 4.7.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from techtonik import NameSetter, SomeClass
>>> ns = NameSetter()
>>> ns.MyObject = SomeClass()
>>> print ns.MyObject
'MyObject'
>>> # QED ;-)
...
>>> ns.copy1 = ns.MyObject  # new name for same object
>>> ns.copy1
<SomeClass obj: () {} assigned to: 'MyObject', 'copy1'>
>>> print ns.MyObject
'MyObject', aka 'copy1'
>>> ns.a = ns.b = ns.c = SomeClass('multi')
>>> ns.a
<SomeClass obj: ('multi',) {} assigned to: 'a', 'b', 'c'>
>>> print ns.b
'a', aka 'b', aka 'c'
>>> ns.b = 123
>>> print ns.b
123
>>> print ns.a
'a', aka '\\b', aka 'c'
>>> ns.a
<SomeClass obj: ('multi',) {} assigned to: 'a', '\\b', 'c'>
>>> nd.d = ns.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'nd' is not defined
>>> ns.d = ns.a
>>> ns.d
<SomeClass obj: ('multi',) {} assigned to: 'a', '\\b', 'c', 'd'>
>>> ns.b = MyObject
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'MyObject' is not defined
>>> ns.b = ns.MyObject
>>> ns.b
<SomeClass obj: () {} assigned to: 'MyObject', 'copy1', 'b'>
>>> ns.a
<SomeClass obj: ('multi',) {} assigned to: 'a', '\\b', 'c', 'd'>
>>> ns.b = ns.a
>>> ns.b
<SomeClass obj: ('multi',) {} assigned to: 'a', '\\b', 'c', 'd', 'b'>
>>> ns.MyObject
<SomeClass obj: () {} assigned to: 'MyObject', 'copy1', '\\b'>
>>>

If you run techtonik.py, it runs a little test, whose output is:
----
[04:37 ~/wk/py]$ techtonik.py
'MyObject'
<SomeClass obj: (1, 2) {'three': 3} assigned to: 'MyObject'>
'MyObject', aka 'mycopy'
<SomeClass obj: (1, 2) {'three': 3} assigned to: 'MyObject', 'mycopy'>
'myinstance'
<SomeClass obj: ('same class new instance',) {} assigned to: 'myinstance'>
'a', aka 'b', aka 'c'
<SomeClass obj: ('multi',) {} assigned to: 'a', 'b', 'c'>
10 20 'a', aka '\\b', aka 'c'
<SomeClass obj: ('multi',) {} assigned to: 'a', '\\b', 'c'>
[04:37 ~/wk/py]$
----
Here is the techtonik.py source:
============================================
#!/usr/bin/python
# debugging ideas for anatoly
# 2014-07-16 00:54:06
#
# The goal is to make something like this:
#
# >>> MyObject = SomeClass()
# >>> print(MyObject)
# 'MyObject'
#
# we can do it with an attribute name space:
# if you can live with prefixing the name space
# name to the names you want to track assignments of:

class NameSetter(object):
    def __setattr__(self, name, val):
        # if our namespace already has the name being assigned ...
        if hasattr(self, name):
            # if that is a nametracking object like a SomeClass instance...
            tgt = getattr(self, name)
            if hasattr(tgt, '_names') and isinstance(tgt._names, list):
                # update its name list to reflect clobbering (prefix '\')
                for i,nm in enumerate(tgt._names):
                    if nm==name: tgt._names[i] = '\\'+ nm
        # if value being assigned has a _names list attribute like SomeClass
        if hasattr(val, '_names') and isinstance(val._names, list):
            val._names.append(name) # add name to assignemt list
        # now store the value, whatever the type
        object.__setattr__(self, name, val) # avoid recursive loop

class SomeClass(object):
    def __init__(self, *args, **kw):
        self.args = args
        self.kw = kw
        self._names = []
    def __str__(self):
        return  ', aka '.join(repr(s) for s in (self._names or 
["(unassigned)"]))
    def __repr__(self):
        return '<%s obj: %r %r %s>' %(
                self.__class__.__name__,
                self.args,
                self.kw,
                'assigned to: %s'%(
                    ', '.join(repr(s) for s in (self._names or 
["(unassigned)"]))))

def test():
    ns = NameSetter()
    ns.target = 'value'
    ns.MyObject = SomeClass(1,2,three=3)
    print ns.MyObject
    print repr(ns.MyObject)
    ns.mycopy = ns.MyObject
    print ns.MyObject
    print repr(ns.MyObject)
    ns.myinstance = SomeClass('same class new instance')
    print ns.myinstance
    print repr(ns.myinstance)
    ns.a = ns.b = ns.c = SomeClass('multi')
    print ns.a
    print repr(ns.b)
    ns.ten = 10
    ns.b = 20
    print ns.ten, ns.b, ns.a
    print repr(ns.a)

if __name__ == '__main__':
    test()

======================================================

Have fun.
Regards,
Bengt Richter


_______________________________________________
pypy-dev mailing list
pypy-dev@python.org
https://mail.python.org/mailman/listinfo/pypy-dev

Reply via email to