propjk007
propjk007

Reputation: 695

Python - Using a class to enable dot notation

Working on a class that has sub properties. Is the below code a good practice / Pythonic? If not, have any suggestion?

GOAL

exp = ExCls()
prop1 = exp.subprop.prop1
exp.print_prop2()
## prop1 = 1
## prints 2

EXAMPLE CODE

class ExCls():
   class subprop:
      prop1 = 1
      prop2 = 2
   def print_prop2(self):
      print self.subprop.prop2

Upvotes: 3

Views: 4024

Answers (2)

Rejected
Rejected

Reputation: 4501

In most of the common higher level languages, dot notation is used to indicate namespace. The same is true for Python. Take the following useless class for example:

>>> class UselessClass(object):
...     @property
...     def and_on(self):
...         return self
...     def forever(self):
...         return "I can see into forever"
>>> this_goes_on = UselessClass()
>>> this_goes_on.and_on.and_on.and_on.and_on.and_on.forever()
'I can see into forever'

All it's doing is returning itself (an instantiated object of type UselessClass), which has access to all of it's own properties.

The only issue with your code is, as GingerPlusPlus pointed out, you're making subprop shared between all instances of ExCls. This may be desired, but (based on the question), also may not be. Here's an instance of why this is bad:

>>> test1 = ExCls()
>>> test2 = ExCls()
>>> test1.subprop.prop1
1
>>> test2.subprop.prop1 = 2
>>> test1.subprop.prop1
2

As you can see, this isn't generally the behaviour you'd expect. Instead, what you may be looking to do is:

class ExCls(object):
    def __init__(self):
        class subprop:
            prop1 = 1
            prop2 = 2
        self.subprop = subprop()

    def print_prop2(self):
        print(self.subprop.prop2)

Overall, I'd highly recommend going back and reading up on Python's Classes, and how they work.

Upvotes: 4

GingerPlusPlus
GingerPlusPlus

Reputation: 5636

I would advice using the right tool for the job – if I'd want my subprop to only contain some data, I'd use types.SimpleNamespace:

from types import SimpleNamespace

class Useless:
    def __init__(self):
        self.subprop = SimpleNamespace(prop1=1, prop2=2)

or, it's close-enough immutable sibling, collections.namedtuple:

from collections import namedtuple

class Useless:
    Subprop = namedtuple('Subprop', 'prop1, prop2')
    def __init__(self):
        # two lines below does the same, choose more readable one
        self.subprop = Subprop(1, 2)
        self.subprop = Subprop(prop1=1, prop=2)

If I'd want it to also contain some methods, I'd use simple, custom object:

class Useless:
    class Subprop:
        def __init__(self, prop1, prop2):
            self.prop1 = prop1
            self.prop2 = prop2
        def sum(self):
            return self.prop1 + self.prop2
    def __init__(self):
        # two lines below does the same, choose more readable one
        self.subprop = Subprop(1, 2)
        self.subprop = Subprop(prop1=1, prop2=2)

Upvotes: 3

Related Questions