How Do I Build a Class with in a Class in Python - python

I am trying to model services and I am having some issue. What I am trying to do is I would want something such as this in code:
>>> service = Service()
>>> service.name = "Instance1"
>>> service.name.color = "red"
>>> service.name.color.enabled = True
I have tried nesting the Classes but I am still having issues.
Is this completely against convention. If so I will reevaluate and find another way to do so.
EDIT:
I decided to do something like the following by just nesting the classes to copy the Hierarchy.
class Service(object):
_prefix = 'Service'
def __init__(self):
self.name = Service.Name()
class Name(object):
_prefix = 'Service'
def __init__(self):
self.color = Service.Name.Color()
class Color(object):
_prefix = 'Service'
def __init__(self, color="N/A"):
self.color = color

It's not against convention to have other objects as values of attributes of your class.
The best thing you can do it declare your desired classes - in your example these would be class Color, which would have a boolean attribute enabled.

I'd avoid having nested classes, for example:
class Color:
def __init__(self, name, enabled=False):
self.name = name
self.enabled = enabled
def __str__(self):
return self.name
class Service:
def __init__(self, name):
self.name = name
self.palette = None
class Palette:
def __init__(self):
self.colors = []
def __str__(self):
return ' - '.join([str(c) for c in self.colors])
if __name__ == "__main__":
num_services = 8
num_colors = 256
offset = num_colors / num_services
palettes = [Palette() for i in range(num_services)]
services = [Service("Service" + str(i)) for i in range(num_services)]
colors = [Color("color" + str(i)) for i in range(num_colors)]
for i in range(num_services):
subcolors = colors[i * offset:(i + 1) * offset]
palettes[i].colors = subcolors
services[i].palette = palettes[i]
print "Palette {0} -> {1}\n".format(i, palettes[i])
Although I'm not sure what's the meaning of enabling a color in this context

If you mean nested instances, you just create them in the relevant __init__ code (or subsequently)
>>> class LR( object):
... def __init__(self, L=None, R=None):
... self.left = L
... self.right = R
>>> class Thing(object):
... def __init__(self):
... self.tree2=LR( LR(1,2), LR(3,4) )
>>> t = Thing()
>>> t.tree2.left.right
2
In this context, Python modules collections.namedtuple and attrs may be of use. (attrs is quite awesome: https://attrs.readthedocs.io/en/stable/).
If you mean some rather deeper magic like Django's nested Meta classes, then the source code is available. (It's clear enough how to use Django, but I can't say I understand the ins and outs of the nested Meta declaration well enough to do anything similar from scratch in my own code).
Class Person( models.Model)
name = models.CharField( max_length = 100)
... # more field declarations
Class Meta:
unique_together = (("name", "birthdate"),)
.... # more Meta-declarations

You should be looking at composition, not nested classes.
class Color:
def __init__(self, name):
self.name = name
class Service:
def __init__(self, color_obj):
self.color_obj = color_obj
service = Service(Color("yellow"))
print(service.color_obj.name)
>> "yellow"

Related

Can i use 'self' in classes on its own?

I have a list of objects of the Person class. This list includes myself, so I need to remove "myself" from the list.
It means I need to remove the object from the list that calls this method.
class Population:
def __init__(self):
self.people = list()
class Person:
def __init__(self):
self.friends_list = list()
def make_friends(self, population, n):
temp_list = population.copy()
temp_list.remove(self)
self.friends_list.extend(random.sample(temp_list,n))
my test:
per = Person()
per2 = Person()
per3 = Person()
per4 = Person()
per5 = Person()
pop = [per,per2,per3,per4,per5]
for per in pop:
per.make_friends(pop, 2)
print('ME: ',per)
print(per.friends_list)
My tests run well, but there are general tests that check the code and they generate an error on this line:
try:
stud_res = person.make_friends(population, count)
except Exception:
print("\tPerson.make_friends() generated error")
return
Can I use self in this way, and if not, how can I better remove "myself" from the list?
It is a perfectly fine use case. By the way, note that you're overriding the builtin list.
To use self, you have to share a list collection between instances of a Person-class. In that case this collection should be declared as a class attribute or global list variable (not an instance attribute).
These samples of code are working:
with global list variable:
class Person:
def __init__(self, name):
self.name = name
def make_friends(self, list):
list.remove(self)
def __repr__(self):
return self.name
p1 = Person("Joe")
p2 = Person("Barack")
the_list = []
the_list.append(p1)
the_list.append(p2)
p1.make_friends(the_list)
print(the_list)
With class attribute:
class Person2:
class_list = []
def __init__(self, name):
self.name = name
Person2.class_list.append(self)
def make_friends(self):
Person2.class_list.remove(self)
def __repr__(self):
return self.name
p1 = Person2("Joe")
p2 = Person2("Barack")
print(Person2.class_list)
p1.make_friends()
print(Person2.class_list)
EDIT:
Variable 3 when a list of people is inside another class.
For accessing a list inside another class you could use attribute name or public method to get it if implemented:
class ClassWithList:
def __init__(self):
self.list_collection = []
def get_list(self):
return self.list_collection
class_with_list = ClassWithList()
class Person:
def __init__(self, name):
self.name = name
def make_friends(self, list):
list.remove(self)
def __repr__(self):
return self.name
p1 = Person("Joe")
p2 = Person("Barack")
# using implemented get-method of instance list attribute
class_with_list.get_list().append(p1)
class_with_list.get_list().append(p2)
print(class_with_list.get_list())
p1.make_friends(class_with_list.get_list())
print(class_with_list.get_list())
# instance list attribute of class`ClassWithList
print(class_with_list.list_collection)
p2.make_friends(class_with_list.list_collection)
print(class_with_list.list_collection)

Python class attributes of the same class

Can a Python class attribute be of the same type?
Something like:
class X:
def __init__(self, inputStr):
a = 0
b = X("Hello")
I am not sure what is the use case you need it for or whether it was a theoretical question. But you might check out class inheritance if that is what you need.
class X:
def __init__(self, inputStr):
a = 0
self.inputStr = inputStr
class Y(X):
pass
obj = Y('Hello')
print(obj.inputStr)

How to have the same updated value of a Parent class be passed down to a inner class?

I need to access the value of an attribute defined at the parent class inside an inner class, here's the code:
class main(object):
def __init__(self):
self.session_id = None
self.devices = self.Devices(self.session_id)
class Devices(object):
def __init__(self, session_id):
self.session_id = session_id
And here's how I would like to use it:
>>> m = main()
>>> m.session_id = 1
>>> m.session_id
1
>>> m.devices.session_id
>>>
My expectation is that m.devices.session_id will always have the exact same value as m.session_id. I understand that at this point when I instantiate the inner class the session_id value is passed down as None because that's how it was initiated but I'm not sure how I can keep both values the same without doing something very ugly like:
m.devices.session_id = m.session_id
outside the class code.
How can I accomplish that inside the class itself ?
The other answer works, but I think this is a better design: lose the nested class, and add a getter on the device object to lookup a backref:
class Main(object):
def __init__(self):
self.session_id = None
self.devices = Devices(main_obj=self)
class Devices(object):
def __init__(self, main_obj):
self.main_obj = main_obj
...
#property
def session_id(self):
return self.main_obj.session_id
The difference here is that you're not storing the same data twice, so they can not get out of sync - there is only one "source of truth" for the session_id (on main object).
In the earlier answer, the data is actually stored in two different namespaces and will get out of sync as easily as m.devices.session_id = 123.
You can do it like this:
class main(object):
def __init__(self):
self._session_id = None
self.devices = self.Devices(self._session_id)
#property
def session_id(self):
return self._session_id
#session_id.setter
def session_id(self, value):
self._session_id = self.devices.session_id = value
class Devices(object):
def __init__(self, session_id):
self.session_id = session_id

Python: manage multiple classes (from serialization) with common properties

I am new to structure Python projects, so please forgive any wrong approaches that could be written down here.
Two JSON schemes represent two objects. These are serialised into classes and have properties in common.
Example:
class TwoWheelVeicle(object):
def __init__(self,v_family, v_subfamily):
self.Family = v_family
self.SubFamily = v_subfamily
self.OtherProp = "other"
class FourWheelVeicle(object):
def __init__(self,v_family):
self.Family = v_family
self.AnotherProp = "another"
def run_an_highway(vehicle):
if isinstance(vehicle,FourWheelVeicle):
return "Wrooom"
if isinstance(vehicle,TwoWheelVeicle):
if veichle.SubFamily in SubFams.NotAllowed:
return "ALT!"
else:
return "Brooom" #forgive me for the sound
class SubFams(object):
NotAllowed = ["Bicycle","50cc"]
Known = ["200cc","Motorbike"]
I am quite unsure of the procedure overall:
- Shall I create an abstract parent class?
- Is NotAllowed stored correctly? This is due to the need of changing its content (that is serialized from some global parameter JSON, it's a #TODO)
..or simply I should not want to do any of these?
Lastly, the code does not allow for any checks if the properties that I serialize are correct (what if SubFamily is unknown? Should it be checked in the decoder?).
A big thank you.
Looks like you should abstract vehicle with a Vehicle class and then subclass it for your different vehicle types.
Your if chain isn't needed if your different subclasses have their own version for that same method.
Something in the line with these:
class Vehicle(object):
def __init__(self, name, cc):
self.name = name
self.cc = cc
self.wheels = None
def runs_on_highway(self):
return self.cc > 50
def sound(self):
pass
class TwoWheels(Vehicle):
def __init__(self, name, cc):
Vehicle.__init__(self, name, cc)
self.wheels = 2
def sound(self):
return 'Brooom.'
class FourWheels(Vehicle):
def __init__(self, name, cc):
Vehicle.__init__(self, name, cc)
self.wheels = 4
def sound(self):
return 'Vruuum'
class ElectricWheels(Vehicle):
def __init__(self, name, cc):
Vehicle.__init__(self, name, 0)
self.wheels = 4
def runs_on_highway(self):
return True
def sound(self):
return 'zzzzz.'
v1 = TwoWheels('Bicycle', 50)
v2 = FourWheels('Motorbike', 200)
v3 = ElectricWheels('ElectricBike', 0)
print(v1.runs_on_highway())
print(v2.runs_on_highway())
print(v3.runs_on_highway())
print(v1.name, v1.cc, v1.wheels, v1.sound())
print(v2.name, v2.cc, v2.wheels, v2.sound())
print(v3.name, v3.cc, v3.wheels, v3.sound())

Expanding the class from object

I have some classes:
class Window(object):
def __init__(self, name):
self.wind_name = name
def getWindowName(self):
return 'wnd' + self.wind_name
class Control(object):
def __init__(self, name, wnd):
self.contrl_name = name
setattr(self, 'getWindowName', wnd.getWindowName)
setattr(self, 'wind_name', wnd.wind_name)
def getControlName(self):
return (self.getWindowName(), 'unk' + self.contrl_name)
class Button(Control):
def __init__(self, name, wnd):
super(Button, self).__init__(name, wnd)
def getControlName(self):
return (self.getWindowName(), 'btn' + self.contrl_name)
wnd = Window('MyApp')
btnOK = Button('OK', wnd)
btnOK.getControlName() # work ok., return ('wndMyApp', 'btnOK')
btnOK.wind_name = 'NewApp'
btnOK.getControlName() # does not work properly., return ('wndMyApp', 'btnOK')
How can I extend the class Control|Button from the object of class Window to access the functions getWindowName and field wind_name in objects btnOK?
Is there a way without creating a field self.wnd = wnd in class Control, or add method setWindowName in Window...?
I can not inherit class Control from the class Window! This is not logical.
Python allows inheriting from multiple classes, i.e.
class Button(Control, Window):
...
But in this case you should know exactly what you are doing (speaking of Pythons Method Resolution Order (MRO)). I'd recommend reading this small book: Python Attributes and Methods.
You can use property for attributes
class Window(object):
def __init__(self, name):
self.wind_name = name
def getWindowName(self):
return 'wnd' + self.wind_name
class Control(object):
def __init__(self, name, wnd):
self.contrl_name = name
self.wnd = wnd
setattr(self, 'getWindowName', wnd.getWindowName)
def get_wind_name(self):
return self.wnd.wind_name
def set_wind_name(self, v):
self.wnd.wind_name = v
wind_name = property(get_wind_name, set_wind_name)
def getControlName(self):
return (self.getWindowName(), 'unk' + self.contrl_name)
class Button(Control):
def __init__(self, name, wnd):
super(Button, self).__init__(name, wnd)
def getControlName(self):
return (self.getWindowName(), 'btn' + self.contrl_name)
wnd = Window('MyApp')
btnOK = Button('OK', wnd)
print btnOK.getControlName() # work ok., return ('wndMyApp', 'btnOK')
btnOK.wind_name = 'NewApp'
print btnOK.getControlName()

Categories