Let me introduce my problem. I am creating a set of objects which are generally Food, but each of them might have completely different set of attributes to set.
I thought to use Factory design pattern, then i faced a problem where and how to set objects attributes and then i found some Builder pattern. However i am not sure if i am at the right path.
Example:
class Food(object):
def __init__(self, taste = None):
self._taste = taste
class Bread(Food):
def __init__(self, flour_type = None):
Food.__init__(self, taste = 'good')
self._flour = flour_type
class Meat(Food):
def __init__(self, type = None, energy_value = None, taste = None):
Food.__init__(self, taste = taste)
self._type = type
self._energy = energy_value
class Soup(Food):
def __init__(self, name = None, recipe = None):
Food.__init__(self, taste = 'fine')
self._name = name
self._recipe = recipe
and then i have a factory like this:
FOOD_TYPES = {'food':Food, 'bread':Bread, 'meat':Meat, 'soup':Soup}
class FoodFactory(object):
#staticmethod
def create_food(food_type):
try:
return FOOD_TYPES[food_type.lower()]()
except Exception:
return None
My question is: I want to pass parameters for constructors but dont know how. Is Builder pattern good idea here or not? The list of attributes might be longer. I was also wondering if passing a context dictionary with attribute name as a key and value as value.
Any ideas how to solve this? Really appreciate any hints and tips.
Regards
Just edit your FoodFactory like this:
class FoodFactory(object):
#staticmethod
def create_food(food_type, **kwargs):
try:
return FOOD_TYPES[food_type.lower()](**kwargs)
except Exception:
return None
Now you can use keyworded arguments for each Food class:
>>> meat = FoodFactory.create_food("meat", energy_value=25)
>>> print meat
>>> print meat._energy
Will print out something like:
>>> <__main__.Meat object at 0x03122AB0>
>>> 25
Hope this helps!
Related
I want to add the inheritance of one or more classes to another class depending on specific requirements; rather than creating multiple subclasses by hand, I want to be able to custom build them on the fly.
For example, the primary class, that would inherit from the others, is Sandwich:
class Sandwich(object):
def __init__(self):
super(Sandwich, self).__init__()
self.bread = "brown"
self.amount = 2
The base classes would be:
class Meat(object):
def __init__(self):
super(Meat, self).__init__()
self.ham = False
self.chicken = False
self.beef = False
class Vegetables(object):
def __init__(self):
super(Vegetables, self).__init__()
self.lettuce = False
self.onion = False
class Vegan(Vegetables):
def __init__(self, *args, **kwargs):
super(Vegetables, self).__init__(*args, **kwargs)
self.vegan_cheese = False
I want to create instances of these classes like this:
meat_sandwich = Sandwich(Meat)
veg_sandwich = Sandwich(Vegetables)
meat_and_veg_sandwich = Sandwich(Meat, Vegetables)
vegan_sandwich = Sandwich(Vegan)
I want to be able to access all variables and methods from these classes, and from the main class.
print(meat_sandwich.bread)
meat_sandwich.ham = True
I have found that you can assign a new class using __new__, however I have only succeeded in replacing the main class, and not setting up multiple inheritance / subclassing:
def __new__(cls, *args, **kwargs):
""" Set to assign any given subclass """
subcls = [i for i in args if isinstance(i, type)]
if subcls:
return super(Sandwich, cls).__new__(*subcls)
else:
return superSandwich, cls).__new__(cls)
Instead of using inheritance in my opinion it makes more sense to use composition here.
This will simplify the construction of the objects, and make it more flexible to change (such as adding new ingredients).
For example, each set of ingredient types could be a separate Enum:
from enum import Enum
class Bread(Enum):
WHITE = "white"
WHOLE_WHEAT = "whole wheat"
BROWN = "brown"
class Meat(Enum):
HAM = "ham"
CHICKEN = "chicken"
BEEF = "beef"
class Vegetable(Enum):
LETTUCE = "lettuce"
ONION = "onion"
class Vegan(Enum):
CHEESE = "vegan_cheese"
Now when defining the sandwich class you could do something like this:
class Sandwich:
def __init__(self, bread, ingredients=None):
self.bread = bread
self.ingredients = ingredients or []
To ask something like (as done in your example) if the sandwich contains ham, you could do:
>>> meat_sandwich = Sandwich(Bread.WHITE, [Meat.HAM])
>>> Meat.HAM in meat_sandwich.ingredients
True
To ask if the sandwich contains no meat, you could do:
>>> veg_sandwich = Sandwich(Bread.BROWN, [Vegetable.LETTUCE])
>>> all(not isinstance(i, Meat) for i in veg_sandwich.ingredients)
True
I've managed to get the results I was after, although I appreciate that I did not explain the problem very well, and suspect this might be something of a hack.
At any rate, I hope this helps illustrate what it was I was trying to achieve, and I would be interested in hearing alternate approaches to this solution.
meat_sandwich = type('meatSandwich_type', (Sandwich, Meat), dict())()
veg_sandwich = type('vegSandwich_type', (Sandwich, Vegetables), dict())()
meat_and_veg_sandwich = type('meatAndVegSandwich_type', (Sandwich, Meat, Vegetables), dict())()
vegan_sandwich = type('meatAndVegSandwich_type', (Sandwich, Vegan), dict())()
I have a class Team, I want to write a Unit test for it,
class name team.py
class Team()
def __init__(self, args):
if args.player:
self.player_name = args.player
self.sports = ''
def test__init__(self):
test1 = team.Team(player="deepak")
While executing this, I am getting error like:
AttributeError: "'str' object has no attribute 'player'"
I know it is very basic but right not I need some quick help to use this. I am not aware how to access this while creating object in test file.
Arguments and keyword arguments don't work like that in python. The closest to what you want would be to use kwargs to get a dict of params.
class Team():
def __init__(self, **kwargs):
if kwargs["player"]:
self.player_name = kwargs["player"]
self.sports = ""
test1 = Team(player="deepak")
See https://docs.python.org/3/tutorial/classes.html for some good docs on how python classes work.
EDIT
Since you can't edit the code, you need to have args be an object with the member player.
from collections import namedtuple
class Team():
def __init__(self, args):
if args.player:
self.player_name = args.player
self.sports = ""
TeamArguments = namedtuple("TeamArguments", ["player"])
test1 = Team(TeamArguments(player="deepak"))
I'm trying to write a method that is supposed to return me an object of a subclass depending on some input data. Let me try to explain
class Pet():
#classmethod
def parse(cls,data):
#return Pet() if all else fails
pass
class BigPet(Pet):
size = "big"
#classmethod
def parse(cls,data):
#return BigPet() if all subclass parsers fails
pass
class SmallPet(Pet):
size = "small"
#classmethod
def parse(cls,data):
#return SmallPet() if all subclass parsers fails
pass
class Cat(SmallPet):
sound = "maw"
#classmethod
def parse(cls,data):
#return Cat() if all criteria met
pass
class Dog(BigPet):
sound = "woof"
#classmethod
def parse(cls,data):
#return Dog() if all criteria met
pass
Imagine that I would like to make a "parser", such as this:
Pet.parse(["big", "woof"])
> returns object of class Dog
Pet.parse(["small", "maw"])
> returns object of class Cat
Pet.parse(["small", "blup"])
> returns object of class SmallPet
I have no idea of how to write this in a proper way. Any suggestions? Of course this is a bullshit example. I'd like to apply this on different packets of a communication protocol of some kind.
If i am approaching this in a completely wrong way, please tell me :)
Why not pass the exact class name, look for that in the globals() and instantiate that?
def parse_pet(class_name, data):
# will raise a KeyError exception if class_name doesn't exist
cls = globals()[class_name]
return cls(data)
cat = parse_pet('Cat', 'meow')
big_pet = parse_pet('BigPet', 'woof')
One of my classes does a lot of aggregate calculating on a collection of objects, then assigns an attribute and value appropriate to the specific object: I.e.
class Team(object):
def __init__(self, name): # updated for typo in code, added self
self.name = name
class LeagueDetails(object):
def __init__(self): # added for clarity, corrected another typo
self.team_list = [Team('name'), ...]
self.calculate_league_standings() # added for clarity
def calculate_league_standings(self):
# calculate standings as a team_place_dict
for team in self.team_list:
team.place = team_place_dict[team.name] # a new team attribute
I know, as long as the calculate_league_standings has been run, every team has team.place. What I would like to be able to do is to scan the code for class Team(object) and read all the attributes, both created by class methods and also created by external methods which operate on class objects. I am getting a little sick of typing for p in dir(team): print p just to see what the attribute names are. I could define a bunch of blank attributes in the Team __init__. E.g.
class Team(object):
def __init__(self, name): # updated for typo in code, added self
self.name = name
self.place = None # dummy attribute, but recognizable when the code is scanned
It seems redundant to have calculate_league_standings return team._place and then add
#property
def place(self): return self._place
I know I could comment a list of attributes at the top class Team, which is the obvious solution, but I feel like there has to be a best practice here, something pythonic and elegant here.
If I half understand your question, you want to keep track of which attributes of an instance have been added after initialization. If this is the case, you could use something like this:
#! /usr/bin/python3.2
def trackable (cls):
cls._tracked = {}
oSetter = cls.__setattr__
def setter (self, k, v):
try: self.initialized
except: return oSetter (self, k, v)
try: self.k
except:
if not self in self.__class__._tracked:
self.__class__._tracked [self] = []
self.__class__._tracked [self].append (k)
return oSetter (self, k, v)
cls.__setattr__ = setter
oInit = cls.__init__
def init (self, *args, **kwargs):
o = oInit (self, *args, **kwargs)
self.initialized = 42
return o
cls.__init__ = init
oGetter = cls.__getattribute__
def getter (self, k):
if k == 'tracked': return self.__class__._tracked [self]
return oGetter (self, k)
cls.__getattribute__ = getter
return cls
#trackable
class Team:
def __init__ (self, name, region):
self.name = name
self.region = region
#set name and region during initialization
t = Team ('A', 'EU')
#set rank and ELO outside (hence trackable)
#in your "aggregate" functions
t.rank = 4 # a new team attribute
t.ELO = 14 # a new team attribute
#see witch attributes have been created after initialization
print (t.tracked)
If I did not understand the question, please do specify which part I got wrong.
Due to Python's dynamic nature, I don't believe there is a general answer to your question. An attribute of an instance can be set in many ways, including pure assignment, setattr(), and writes to __dict__ . Writing a tool to statically analyze Python code and correctly determine all possible attributes of an class by analyzing all these methods would be very difficult.
In your specific case, as the programmer you know that class Team will have a place attribute in many instances, so you can decide to be explicit and write its constructor like so:
class Team(object):
def __init__(name ,place=None):
self.name = name
self.place = place
I would say there is no need to define a property of a simple attribute, unless you wanted side effects or derivations to happen at read or write time.
In python, I can alter the state of an instance by directly assigning to attributes, or by making method calls which alter the state of the attributes:
foo.thing = 'baz'
or:
foo.thing('baz')
Is there a nice way to create a class which would accept both of the above forms which scales to large numbers of attributes that behave this way? (Shortly, I'll show an example of an implementation that I don't particularly like.) If you're thinking that this is a stupid API, let me know, but perhaps a more concrete example is in order. Say I have a Document class. Document could have an attribute title. However, title may want to have some state as well (font,fontsize,justification,...), but the average user might be happy enough just setting the title to a string and being done with it ...
One way to accomplish this would be to:
class Title(object):
def __init__(self,text,font='times',size=12):
self.text = text
self.font = font
self.size = size
def __call__(self,*text,**kwargs):
if(text):
self.text = text[0]
for k,v in kwargs.items():
setattr(self,k,v)
def __str__(self):
return '<title font={font}, size={size}>{text}</title>'.format(text=self.text,size=self.size,font=self.font)
class Document(object):
_special_attr = set(['title'])
def __setattr__(self,k,v):
if k in self._special_attr and hasattr(self,k):
getattr(self,k)(v)
else:
object.__setattr__(self,k,v)
def __init__(self,text="",title=""):
self.title = Title(title)
self.text = text
def __str__(self):
return str(self.title)+'<body>'+self.text+'</body>'
Now I can use this as follows:
doc = Document()
doc.title = "Hello World"
print (str(doc))
doc.title("Goodbye World",font="Helvetica")
print (str(doc))
This implementation seems a little messy though (with __special_attr). Maybe that's because this is a messed up API. I'm not sure. Is there a better way to do this? Or did I leave the beaten path a little too far on this one?
I realize I could use #property for this as well, but that wouldn't scale well at all if I had more than just one attribute which is to behave this way -- I'd need to write a getter and setter for each, yuck.
It is a bit harder than the previous answers assume.
Any value stored in the descriptor will be shared between all instances, so it is not the right place to store per-instance data.
Also, obj.attrib(...) is performed in two steps:
tmp = obj.attrib
tmp(...)
Python doesn't know in advance that the second step will follow, so you always have to return something that is callable and has a reference to its parent object.
In the following example that reference is implied in the set argument:
class CallableString(str):
def __new__(class_, set, value):
inst = str.__new__(class_, value)
inst._set = set
return inst
def __call__(self, value):
self._set(value)
class A(object):
def __init__(self):
self._attrib = "foo"
def get_attrib(self):
return CallableString(self.set_attrib, self._attrib)
def set_attrib(self, value):
try:
value = value._value
except AttributeError:
pass
self._attrib = value
attrib = property(get_attrib, set_attrib)
a = A()
print a.attrib
a.attrib = "bar"
print a.attrib
a.attrib("baz")
print a.attrib
In short: what you want cannot be done transparently. You'll write better Python code if you don't insist hacking around this limitation
You can avoid having to use #property on potentially hundreds of attributes by simply creating a descriptor class that follows the appropriate rules:
# Warning: Untested code ahead
class DocAttribute(object):
tag_str = "<{tag}{attrs}>{text}</{tag}>"
def __init__(self, tag_name, default_attrs=None):
self._tag_name = tag_name
self._attrs = default_attrs if default_attrs is not None else {}
def __call__(self, *text, **attrs):
self._text = "".join(text)
self._attrs.update(attrs)
return self
def __get__(self, instance, cls):
return self
def __set__(self, instance, value):
self._text = value
def __str__(self):
# Attrs left as an exercise for the reader
return self.tag_str.format(tag=self._tag_name, text=self._text)
Then you can use Document's __setattr__ method to add a descriptor based on this class if it is in a white list of approved names (or not in a black list of forbidden ones, depending on your domain):
class Document(object):
# prelude
def __setattr__(self, name, value):
if self.is_allowed(name): # Again, left as an exercise for the reader
object.__setattr__(self, name, DocAttribute(name)(value))