Python Forum
Getting names from object dot-syntax acess
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Getting names from object dot-syntax acess
#1
Hello,
I'm trying to create a object which can use the names provided by python-dot-syntax.
I would use these names as a path to lookup for data in another data structure, which would then check if the provided path exist or not.

s = Shell()
print(s.this.is.a.path)
# [out]: "appropriate_paths_value" if found value for `this.is.path` in the data structure OR
# [out]: None if not found
It is worth noticing that Shell in this example does not hold the data. It should just get the path `"this.is.a.path" and ask the data structure, which is another object, if it exists.


I've tried implementing this using __getattribute__, but I can't know when a given line has finished evaluating, therefore I cannot separate names from different dot-chains.

This is the prototype I've been working:

def main():
    a = DotGetter()
    print(f"{a.foo.bar=}")
    # [out]: ["foo", "bar"] (ok)
    # [expected]: ["foo", "bar"]

    print(f"{a.spam=}")
    # [out]: ["foo", "bar", "spam"] (not ok)
    # [expected]: ["spam"]


class DotGetter:
    """
    d = DotGetter()
    d.foo.bar -> ["foo", "bar"]
    d.spam -> ["spam"]
    """

    def __init__(self, path: list[str] | None = None):
        self._path = path if path else []

    def __getattribute__(self, name):
        # special name handling
        if not name.startswith("_") and not name.startswith("__"):
            self_path = object.__getattribute__(self, "_path")
            self_path.append(name)
            return DotGetter(self_path)

        # normal name handling
        return object.__getattribute__(self, name)

    def __repr__(self):
        return str(self._path)


if __name__ == "__main__":
    exit(main())
I guess I need some kind of hook to be called when the __getattribute__ chain in the same line has finished, but I've no idea if this is even possible.
I've wondered if I can live inspect the stack trace to determine that, but that's a long shot.

There are some other approaches to achieve this lookup while still using dot notation, like making a lookup to the data structure on each access, but this solution would make a more clean and decoupled design than the alternatives I've considered.

Any help is appreciated,
Thanks!
Reply
#2
Are you thinking of something like this?
import inspect

def tracker(path, context=None):
    if context is None:
        context = inspect.currentframe().f_back.f_locals
    parts = iter(path.split("."))
    obj = context[next(parts)]
    for part in parts:
        obj = getattr(obj, part)
    return obj


class A:
    def __init__(self, number, string):
        self.number = number
        self.string = string


class B:
    def __init__(self, *args):
        self.a = A(1, args[0])
        self.b = A(2, args[1])


x = B("one", "two")
y = B("cow", "chicken")

while path := input("Path: "):
    print(tracker(path))
Output:
Path: x.a.string one Path: y.b.string chicken Path: x.b.number 2 Path:
This returns the value of the attribute, but you could wrap a verification function around tracker() that catches key and attribute errors.
def verify(path, context=None):
    try:
        if context is None:
            context = inspect.currentframe().f_back.f_locals
        tracker(path, context)
    except (KeyError, AttributeError):
        return False
    return True
pedropessoa likes this post
Reply
#3
That's not exatcly what I want, although it's a quite interesting usage of inspect. This may help me getting started with some ideas.

But being more specific, the data structure is an object T which have a method T.get_by_path(path: sequence[str]) that return the data.

The role of myobj there is to fake that it can have any attribute (and that it's attributes can have any attributes too) so, when some code tries to access some arbitrary attribute chain starting from myobj, myobj will read and join them in a sequence, call T.get_by_path(joined_dot_path) and return the value. Eg:

myobj = DotGetter()
# so that
a = myobj.some.path
# would behave exatcly like:
a = T.get_by_path(["some", "path"])
This code is intended for a library, so it is really a lib-user experience feature.
I may try some different approach if this sounds too unreasonable.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Acess variables from class samuelbachorik 3 1,905 Aug-20-2021, 02:55 PM
Last Post: deanhystad
  acess particular element in dataframe using .loc operator. shantanu97 0 1,430 Jun-30-2021, 03:59 AM
Last Post: shantanu97
  Printing Object Names JoeDainton123 5 2,767 May-09-2021, 10:33 PM
Last Post: deanhystad

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020