0
class first:
    class second:
        class third:
            class forth:
                val = "test"

I wanted to safely retrieve the variable 'val' and if 'val' doesn't exist i wanted to return False (instead of showing error)

I know i can use logical operator like this :

print first.second and first.second.third and first.second.third.forth and first.second.third.forth.val or False

or put it in a 'try ... except' block like this :

try :
    print first.second.third.forth.val
except AttributeError:
    pass

but both example above is just too long to read especially when they are too many nested classes

My question is, is there any other simpler way to do this? I wish for something like the ?. operator in C# or atleast function that can evaluate it safely and easy to read.

My question is similar to this question : How to know if an object has an attribute in Python

But the difference is that mine is in nested class, if i use hasattr() or getattr() I'll still have error when one the the class is missing like this :

>>> class first:
...         class second:
...             class third:
...                 class forth:
...                     val = "test"
... 
>>> hasattr(first.second.third.forth.fifth,'val')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class forth has no attribute 'fifth'

But it does give me an idea to create a function like this :

>>> def eval(cls, args, default=False):
...     for arg in args.split('.') :
...         if not hasattr(cls,arg) : return default
...         cls = getattr(cls,arg)
...     return cls
... 
>>> eval(first,'second.third.forth.val','Default Value')
'test'
>>> eval(first,'second.third.forth.fifth','Default Value')
'Default Value'
Community
  • 1
  • 1
SDBot
  • 784
  • 1
  • 4
  • 10
  • 1
    Having several levels of nested classes like that is going to make you code more difficult to read. Try to flatten it out if possible. – TigerhawkT3 Mar 28 '16 at 09:41
  • x?.y – null conditional member access. Returns null if the left hand operand is null. This does not talk existence. – saikumarm Mar 28 '16 at 09:43
  • @TigerhawkT3 Thanks, I'll try flatten it whenever possible. – SDBot Mar 28 '16 at 09:59
  • @saikumarm what does "This does not talk existence" mean? – SDBot Mar 28 '16 at 10:00
  • @SDBot I don't think you should be bringing counterfactual conditionals into programming. It will only complicate your code without any benefits. – Stop harming Monica Mar 28 '16 at 10:34
  • 1
    From [PEP-020: The Zen of Python](https://www.python.org/dev/peps/pep-0020/): "Flat is better than nested.". – Kevin J. Chase Mar 28 '16 at 11:22
  • See [Carl Meyer's answer](http://stackoverflow.com/a/611708/4116239) to a near-duplicate of this question. – Kevin J. Chase Mar 28 '16 at 22:37
  • Possible duplicate of [How to know if an object has an attribute in Python](http://stackoverflow.com/questions/610883/how-to-know-if-an-object-has-an-attribute-in-python) – Kevin J. Chase Mar 28 '16 at 22:38
  • @KevinJ.Chase thanks for linking me to that question, it's a bit different but it does help me solved my problem. – SDBot Mar 29 '16 at 04:37

3 Answers3

2

It might be a matter of personal taste, but there is a "better ask forgiveness than permission" school of thought in Python, and your try/except fits there. (I would do it like that, FWIW.)

About the long expression due to your multiple nesting:

  1. Consider if you actually need this much nesting in any case.
  2. If you do need this much nesting, but the access expression is too long, you could break it up:

    try :
        second = first.second
        third = second.third
        forth = third.forth
        print forth.val
    except AttributeError:
        pass
    
Community
  • 1
  • 1
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
  • I try not to use "try .. except" block because there are just too many nested classes like that. – SDBot Mar 28 '16 at 10:21
0

I answering my own question so that it can be mark as solved.

I am currently using this method, please let me know if you have a better solution.

>>> def eval(cls, args, default=False):
...     for arg in args.split('.') :
...         if not hasattr(cls,arg) : return default
...         cls = getattr(cls,arg)
...     return cls
... 
>>> eval(first,'second.third.forth.val','Default Value')
'test'
>>> eval(first,'second.third.forth.fifth','Default Value')
'Default Value'
SDBot
  • 784
  • 1
  • 4
  • 10
-1

string value = first.second.third.forth.val; bool isValue = string.NullOrEmpty(value) ? false : value;

Sonu
  • 25
  • 8