Reputation: 695
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
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
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