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())
Related
I would like to access the instance variable (orders) of a class (DailyOrders) from the init of another, keeping in mind that the class containing the instance variable is a parent to the other. This seems to perfect use for inheritance but I couldn't get it to work. Here is the code.
class DailyOrders():
PRICE_PER_DOZEN = 6.5
def __init__(self, day):
self.orders = []
self.day = day
def total_eggs(self):
total_eggs = 0
for order in self.orders:
total_eggs += order.eggs
return total_eggs
def show_report(self):
if self.total_eggs() < 0:
print("No Orders")
else:
print(f"Summary:\nTotal Eggs Ordered: {self.total_eggs()}\n*********")
print(f"Average Eggs Per Customer: {self.total_eggs() / len(self.orders):.0f}")
class EggOrder():
def __init__(self, eggs=0, name=""):
if not name:
self.new_order()
else:
self.name = name
self.eggs = eggs
orders.append(self)
def new_order(self):
self.name = string_checker("Name: ")
self.eggs = num_checker("Number of Eggs: ")
def get_dozens(self):
if self.eggs % 12 != 0:
dozens = int(math.ceil(self.eggs / 12))
else:
dozens = self.eggs / 12
return dozens
def show_order(self):
print(f"{self.name} ordered {self.eggs} eggs. The price is ${self.get_dozens() * DailyOrders.PRICE_PER_DOZEN}.")
if __name__ == "__main__":
friday = DailyOrders("Friday")
friday_order = EggOrder(12, "Someone")
friday_order.show_order()
friday.show_report()
saturday = DailyOrders("Saturday")
saturday_order = EggOrder(19, "Something")
saturday_order.show_order()
saturday.show_report()
I have not tried using inheritance before, but one proposed solution is to use
super(EggOrder, self).__init__() but this made me provide the day, as it was going to create another instance of the DailyOrders class. I don't want this.
Just inherit and user super to call the parent initializer:
class DailyOrders:
def __init__(self, day):
self.orders = []
# ...
class EggOrder(DailyOrders):
def __init__(self, day, eggs=0, name=""):
super().__init__(day)
# Now self.orders is available.
Keep in mind that if the parent initializer receives any parameter, the child must receive it as well in order to be able to pass it.
Not providing a day param ...
If you don't want to provide a day param you should have another class with the interface/functionality that's common to the others, and the inherit from such base class:
class BaseOrders:
def __init__(self):
self.orders = []
# ...
class DailyOrders(BaseOrders):
def __init__(self, day):
super().__init__()
# Now self.orders is available.
self.day = day
# ...
class EggOrder(BaseOrders):
def __init__(self, eggs=0, name=""):
super().__init__()
# Now self.orders is available.
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"
Given that I need to operate a machine, I need a
VendingMachine class:
Property is a stock(list) that stores Food items.
Methods:
Constructor takes in no arguments.
get_stock_names(): returns a list of strings that represents the names of
all food items in the stock.
load(food): adds the Food object to stock
and others,
#predefined
class Food(object):
def __init__(self, name, nutrition, good_until):
self.name = name
self.nutrition = nutrition
self.good_until = good_until
self.age = 0
def get_name(self):
return str(self.name)
def get_age(self):
return self.age
def get_nutrition(self):
if self.age <= self.good_until:
return self.nutrition
else:
return 0
def ripen(self, days):
self.age = self.age + days
return self.age
def is_spoiled(self):
return self.good_until < self.age
#my code below
class VendingMachine:
def __init__(self):
Property = Food.get_name #no clue how to make a Property
self.load = Food.load #same here
def get_stock_names(self, Property):
lst = []
for i in Food:
i = str(i)
lst.append(i)
return lst
def has_stock(self, name):
return name in Property
def load(self, food):
Property.append(food)
return Property
def sell(self, name):
if name in Property:
Property.remove(name)
return name
else:
return None
What I get is
AttributeError: 'VendingMachine' object has no attribute 'load' (a variable)
I'm pretty sure you've misunderstood the line of your instructions telling you about the stock property. I suspect it is just telling you to make an instance variable named self.stock which holds a list of Food instances. Since the constructor takes no arguments, it presumably starts empty. Using the term "property" seems like a red herring, since property has a specific meaning in Python (a wrapper around a method to make it look like an attribute), which doesn't make much sense in this situation.
Anyway, here's what I think you want your constructor to look like:
def VendingMachine(object):
def __init__(self):
self.stock = [] # initially empty
Your later methods can inspect or manipulate self.stock as necessary.
Considering these classes
class Foo(object):
def __init__(self, owner):
self.owner = owner
self.a = None
self.b = []
object = Foo(mike)
each hour, i need to check if Foo is updated (object.a or object.b has changed)
How can i do ?
Do i need to create a new object object2=Foo(mike) and parse attribute to compare with object, put the difference into a list or is there a pythonic way to do it ?
If a create two objects, parse them to build 2 lists and compare them is a good idea ?
If you have this problem, do not allow anything to change attributes directly.
Use methods instead (e.g. add_b(self, value), set_a(self, value)) in which you can keep control on what's happening.
Try using properties.
E.g.
class Foo(object):
__owner = None
__changed = False
def __init__(self, owner):
self.__owner = owner
def get_owner(self):
return self.__owner
def set_owner(self, owner):
old_owner = self.__owner
if owner != old_owner:
self.__changed = True
self.__owner = owner
owner = property(get_owner, set_owner)
#property
def changed(self):
return self.__changed
f = Foo('bar')
print f.owner # bar
f.owner = 'bar2'
print f.owner # bar2
print f.changed # True
I have a Category class which has different names for each categories, the names of the categories can be unknown, good and bad, all categories share the same behavior so i don't want to create sub classes for each type of category, the problem comes when i am trying to
create the different categories in this way:
Category.GOOD
This statement should return a category object with his name setting to 'good' so i try
the following:
class Category(object):
def __init__(self, name):
self.name = name
#property
def GOOD(self):
category = Category(name='good')
return category
#property
def BAD(self):
category = Category(name='bad')
return category
Then i created and use the category with the following output:
c = Category.GOOD
c.name
AttributeError: 'property' object has no attribute 'name'
Realizing that this doesn't work i try a java like approach:
class Category(object):
GOOD = Category(name='good')
BAD = Category(name='bad')
def __init__(self, name):
self.name = name
What i get here is a undefined name "Category" error, so my question is if there is a pythonic way to create a category object like this.
You probably want to use classmethods:
class Category(object):
#classmethod
def GOOD(cls):
category = cls(name='GOOD')
return category
Now you can do c = Category.GOOD().
You cannot do this with a property; you either have to use a classmethod, or create your own descriptor for that:
class classproperty(property):
def __get__(self, inst, cls):
return self.fget(cls)
I'm abusing the property decorator here; it implements __set__ and __del__ as well, but we can just ignore those here for convenience sake.
Then use that instead of property:
class Category(object):
def __init__(self, name):
self.name = name
#classproperty
def GOOD(cls):
return cls(name='good')
#classproperty
def BAD(cls):
return cls(name='bad')
Now accessing Category.GOOD works:
>>> Category.GOOD
<__main__.Category object at 0x10f49df50>
>>> Category.GOOD.name
'good'
I'd use module variables for this. Consider you have the module category.py:
class Category(object):
# stuff...
now you put the two global objects in it:
GOOD = Category(name='good')
BAD = Category(name='bad')
You can use it like that:
from path.to.category import GOOD, BAD
I don't say that this is pythonic but I think this approach is elegant.
The main point that you could not use class definition inside that class definition itself. So the most straight way to achieve what you are want is to use class/static methods as shown below, or even package constants.
class Category(object):
def __init__(self, name):
self.name = name
#classmethod
def GOOD(cls):
return Category(name='good')
#classmethod
def BAD(cls):
return Category(name='bad')
print Category.GOOD().name
or
class Category(object):
def __init__(self, name):
self.name = name
#staticmethod
def GOOD():
return Category(name='good')
#staticmethod
def BAD():
return Category(name='bad')
print Category.GOOD().name