1

I don't know what to call this but I've done it in TCL and Elixir. It's when you substitute a variable to make the code simpler. That's a terrible way of explaining it. The example will make it clear:

Here's regular code:

def get(self, item):
    if item == 'name':
        return self.name
    elif item == 'age':
        return self.age

I'd like to turn that into something like this:

def get(self, item):
    return self.%{item}

Where it interprets the value in the variable item as the name of a variable. like I said, I've done stuff like this in other languages but I don't know what it's called and I don't know how to do it in python.

Can you help me? What is this ability/style called? Also, how do you do it in Python?

PS. Here's a trivial example from TCL

c:\repos\flow>tclsh
% set foo bar
bar
% set bar baz
baz
% puts $foo
bar
% puts [set $foo]
baz

See how [set $foo] essentially told the interpreter to interpret $foo's value as a variable name which was the variable bar then the command puts took bar as a variable and printed out its value which was the string baz

You can even do this kind of thing with commands in Tcl

% set a puts
puts
% $a hello\ world
hello world
MetaStack
  • 3,266
  • 4
  • 30
  • 67
  • What's wrong with accessing `self.name` directly? – Skam Feb 07 '18 at 04:24
  • I don't know if it matters, but in this example I guess. `item` would be a variable passed into the `def` so it wouldn't be part of the instance of the class object but in this case, what its referring to would be an instance variable such as `name` as in `myInstance.get('name')` – MetaStack Feb 07 '18 at 04:29
  • there's nothing wrong with it, I'm just trying to learn another way to do it. is it not possible to do such things in Python? – MetaStack Feb 07 '18 at 04:30
  • Basically, I'm looking for the syntax that says to the python interpreter, "I'm giving you a variable but I want to look at the value of this variable and then interpret that value as the name of a variable instead of as a string or something else." – MetaStack Feb 07 '18 at 04:34
  • 1
    [This](https://stackoverflow.com/questions/610883/how-to-know-if-an-object-has-an-attribute-in-python) might be what you're looking for but I'm not entirely sure. Can you post a TCL or Elixir equivalent? – Skam Feb 07 '18 at 04:39
  • that's useful, thanks but it's not exactly what I'm referencing. I've put a Tcl example up. – MetaStack Feb 07 '18 at 04:48

2 Answers2

4

You can use getattr:

def get(self, item):
  return getattr(self, item)

getattr can also be used like getattr(object, attrname), and it behaves in the same way.

However, having to do this is usually bad practice. You should probably be using a dictionary instead. An example with a dictionary:

def __init__(self, whatever):
  self.stuff = {"name": "bob", "age": 40}

def get(self, item):
  return self.stuff[item]

See also: this

If you want to get variables from the global or local scopes, you can use:

a = 1
def f():
  b = 2
  print(globals()["a"])
  #print(globals()["b"]) fails, b is not global
  print(locals["b"]) # works, b is in the local scope

There is also a very general way (also very ugly and insecure):

foo="bar"
bar="baz"
baz = ""
obj=None
eval(f"obj.{foo}") # obj.bar
eval(f"obj.{eval(f'{foo}')}") # obj.baz
eval(f"{foo}") # bar / "baz"
eval(f"{eval(f'{foo}')}") # baz / ""

Please never use this.

internet_user
  • 3,149
  • 1
  • 20
  • 29
  • That's awesome for this case, but is there a more generalized approach. I just used the case of Class attribute because that's what I am working on but I really care about learning the general ability in python if it's possible. How could I use a dictionary in this case? How do I do it generally? – MetaStack Feb 07 '18 at 04:50
  • 1
    What do you mean generally? Like for any object, not just one with a `.get`? – internet_user Feb 07 '18 at 04:53
  • I think that's exactly what I mean – MetaStack Feb 07 '18 at 04:54
1

You can try this approach:

class foo():
    cls_attr = "hello"
    def __init__(self):
        self.name = "i am foo"
        self.age = 0
        self.gender = None
        self.bar = "this is bar"
    def get(self, item):
        if item in foo.__dict__:
            return foo.__dict__[item]
        elif item in self.__dict__:
            return self.__dict__[item]
        else:
            return None

>>> f = foo()
>>> f.get('gender')
>>> f.get('bar')
'this is bar'
>>> f.get('name')
'i am foo'
>>> f.get('nothing')
>>> f.get('age')
0
>>> f.get('cls_attr')
'hello'

Updated my answer based on internet_user's comment. Now it should return both instance and class attributes.

Edit: Okay I don't know how to do the superclass attributes (I mean I can probably guess it's super().__dict__), but at the end of the day internet_user's answer is a better version. I'll leave this answer here for future viewers to see the inefficient approach for comparison.

r.ook
  • 13,466
  • 2
  • 22
  • 39
  • This won't work with class attributes. (i.e. `foo.a = 1`) – internet_user Feb 07 '18 at 04:55
  • 1
    @LegitStack it lists the object’s (writable) attributes. The `[]` is just requesting the key `item` of the returned dictionary to get the value if it exists. You can use [`__dict__`](https://docs.python.org/3/library/stdtypes.html#object.__dict__) on most objects. – r.ook Feb 07 '18 at 04:57
  • This is wonderful but is there really no generalized syntax? what if I wanted to variable substitute just regular old variables like `foo = 'bar'; bar = 'baz'; print(variable_substitute(foo)); ----> 'baz'` – MetaStack Feb 07 '18 at 05:02
  • @internet_user I've updated my answer to use `foo.__dict__` instead, which also returns class attributes. – r.ook Feb 07 '18 at 05:06
  • What about superclasses? – internet_user Feb 07 '18 at 05:10
  • I've edited the post again, but I'll go ahead and assume I'm missing something else again :) (knew it) – r.ook Feb 07 '18 at 05:10
  • 1
    Yeah, this is why you use `getattr`. It gets pretty messy otherwise. – internet_user Feb 07 '18 at 05:11
  • As I'm searching the internet for this I think I may have come across the name of this style of programming, but maybe I'm mistaken, "MetaProgramming" maybe? Thanks for all your guy's help! This is good stuff. Perhaps in Python it's not explicitly built into the language syntax like other languages, but there perhaps are, as you both have shown, niche ways to accomplish the same style in various situations. I don't know I'll keep looking. – MetaStack Feb 07 '18 at 05:11
  • 1
    @LegitStack in response to your question, you can use do `def set(self, item, value): return setattr(self, item, value)` in the vein of internet_user's answer. – r.ook Feb 07 '18 at 05:18