I'm having problems designing a (Python) switch pattern that works well
with object composition. More specifically I want to create a function that gets an 'entity_id' as argument (+other relevant arguments), creates an object and matching components for it (possibly using the additional arguments). Here is a toy example
class Entity:
def __init__(self,name,animal=None,item=None):
self.name = name
class Animal: # Animal component
def __init__(self,legs):
self.legs = legs
class Item: # Item component
def __init__(self,quantity):
self.quantity = quantity
I'd like to have something like:
def place_entity(entity_id,quantity=1):
switch (entity_id):
case 'emu':
animal_component = Animal(2)
ent = Entity('Emu', animal_component)
break
case 'apple':
item_component = Item(quantity)
ent = Entity('Apple(s)', item_component )
break
return(ent)
It would be easy to produce the above using a for loop and if statements, but is there a better way?
It should be easy to
add new types of entities (bananas, nails, sharks, etc.),
add new components (Edible for instance, which tells
if entity is question is edible and how many calories it contains),
without having to change the code in too many places. Note that components sometimes require additional arguments (that are given in the input of the function).
I have seen switch statements replaced by dictionaries, but my implementation (below) of it turned out horrid. Adding another component requires adding code to every entity function!
Also I don't know how to pass arguments to components in an elegant way. Additional arguments do not work in this implementation. That is if I wanted to create an entity (a batch) of apples (let's say quantity=5) I would have to modify every type of entity function to accept a quantity argument (even if it doesn't use it), or modify the quantity after the entity is created (this is not smart since if one uses if statements then one might as well use for loop+if statements).
def create_entity(entity_id,quantity=None):
def emu():
animal_component = Animal(2)
entity_data = {'name':'Emu','animal_component':animal_component,
'item_component':None}
return(entity_data)
def apple(quantity=1):
item_component = Item(quantity)
entity_data = {'name':'Apple(s)','animal_component':None,
'item_component':item_component}
return(entity_data)
entity_dict = {'emu':emu,'apple':apple}
entity_data = entity_dict[entity_id]()
ent = Entity(entity_data['name'], animal=entity_data['animal_component'],
item=entity_data['item_component'])
return(ent)
You can simulate a switch statement using this function definition:
def switch(v): yield lambda *c: v in c
Usage would be very close to what you're looking for:
for case in switch (entity_id):
if case('emu'):
animal_component = Animal(2)
ent = Entity('Emu', animal_component)
break
if case('apple'):
item_component = Item(quantity)
ent = Entity('Apple(s)', item_component )
break
Related
I only need to use operatorDict one time to determine which operation I am using for the class. What is the most pythonic way to store the correct operator inside of self._f ?
class m:
def __init__(self,n,operator,digit1,digit2):
self._operatorDict = {'+':add, '-':sub, 'x':mul, '/':truediv}
self._f = self._operatorDict[operator]
self._score = 0
self._range = n
self._aMin, self._aMax = getMaxMinDigits(digit1)
self._bMin, self._bMax = getMaxMinDigits(digit2)
Much of this depends on how much of the operatorDict you want to expose. In this case, I'd probably recommend one of two things.
Option 1: Put the dict on the class:
class m:
_operatorDict = {'+':add, '-':sub, 'x':mul, '/':truediv}
def __init__(self,n,operator,digit1,digit2):
self._f = self._operatorDict[operator]
self._score = 0
self._range = n
self._aMin, self._aMax = getMaxMinDigits(digit1)
self._bMin, self._bMax = getMaxMinDigits(digit2)
Since the _operatorDict isn't going to mutate inside the class, it doesn't really seem necessary to have it as a instance attribute. However, it still belongs to the class in some sense. This approach also allows you to change the operatorDict as necessary (e.g. in a subclass).
Option 2: Put the dict in the global namespace:
_operatorDict = {'+':add, '-':sub, 'x':mul, '/':truediv}
class m:
def __init__(self,n,operator,digit1,digit2):
self._f = _operatorDict[operator]
self._score = 0
self._range = n
self._aMin, self._aMax = getMaxMinDigits(digit1)
self._bMin, self._bMax = getMaxMinDigits(digit2)
The advantages here are similar to before -- mainly that you only create one operatorDict and not one per instance of m. It's also a little more rigid in that this form doesn't really allow for easy changing of the operatorDict via subclassing. In some cases, this rigidity can be desirable. Also, as some noted in the comments, if you use this second option, naming _operatorDict to indicate that it is a constant in your naming system (e.g. _OPERATOR_DICT in pep8) is probably a good idea.
I'm writing some tooling for online programming contexts.
Part of it is a test case checker which actually based on a set of pairs of (input, output) files are gonna check whether the solution method is actually working.
Basically, the solution method is expected to be defined as follow:
def solution(Nexter: inputs):
# blahblah some code here and there
n = inputs.next_int()
sub_process(inputs)
# simulating a print something
yield str(n)
can be then translated (once the AST modifications) as:
def solution():
# blahblah some code here and there
n = int(input())
sub_process()
print(str(n))
Note: Nexter is a class defined to be whether a generator of user input() calls or carry out the expected inputs + some other goodies.
I'm aware of the issues related to converting back to source code from the AST (requires to rely on 3rd party stuff). I also know that there is a NodeTransformer class:
http://greentreesnakes.readthedocs.io/en/latest/manipulating.html
https://docs.python.org/3/library/ast.html#ast.NodeTransformer
But its use remains unclear to me I don't know if I'm better off checking calls, expr, etc.
Here is below what I've ended up with:
signature = inspect.signature(iterative_greedy_solution)
if len(signature.parameters) == 1 and "inputs" in signature.parameters:
parameter = signature.parameters["inputs"]
annotation = parameter.annotation
if Nexter == annotation:
source = inspect.getsource(iterative_greedy_solution)
tree = ast.parse(source)
NexterInputsRewriter().generic_visit(tree)
class NexterInputsRewriter(ast.NodeTransformer):
def visit(self, node):
#???
This is definitely not the best design ever. Next time, I would probably go for the other way around (i.e. having a definition with simple user defined input() (and output, i.e. print(...)) and replacing them with test case inputs) when passing to a tester class asserting whether actual outputs are matching expecting ones.
To sum up this what I would like to achieve and I don't really know exactly how (apart of subclassing the NodeTransformer class):
Get rid of the solution function arguments
Modifiy the inputs calls in method body (as well as in the sub calls of methods also leveraging Nexter: inputs) in order to replace them with their actual user input() implementation, e.g. inputs.next_int() = int(input())
EDIT
Found that tool (https://python-ast-explorer.com/) that helps a lot to visualize what kind of ast.AST derivatives are used for a given function.
You can probably use NodeTransformer + ast.unparse() though it wouldn't be as effective as checking out some other 3rd party solutions considering it won't preserve any of your comments.
Here is an example transformation done by refactor (I'm the author), which is a wrapper layer around ast.unparse for doing easy source-to-source transformations through AST;
import ast
import refactor
from refactor import ReplacementAction
class ReplaceNexts(refactor.Rule):
def match(self, node):
# We need a call
assert isinstance(node, ast.Call)
# on an attribute (inputs.xxx)
assert isinstance(node.func, ast.Attribute)
# where the name for attribute is `inputs`
assert isinstance(node.func.value, ast.Name)
assert node.func.value.id == "inputs"
target_func_name = node.func.attr.removeprefix("next_")
# make a call to target_func_name (e.g int) with input()
target_func = ast.Call(
ast.Name(target_func_name),
args=[
ast.Call(ast.Name("input"), args=[], keywords=[]),
],
keywords=[],
)
return ReplacementAction(node, target_func)
session = refactor.Session([ReplaceNexts])
source = """\
def solution(Nexter: inputs):
# blahblah some code here and there
n = inputs.next_int()
sub_process(inputs)
st = inputs.next_str()
sub_process(st)
"""
print(session.run(source))
$ python t.py
def solution(Nexter: inputs):
# blahblah some code here and there
n = int(input())
sub_process(inputs)
st = str(input())
sub_process(st)
I have a function that checks an object for some properties and returns boolean values depending on the result. It's too complex to write it in filter, but it works and returns the right value.
Now I want to use sqlalchemy to return all objects that this function returns True for. I tried:
DBSession.query(MyObject).filter(self.check_attributes(MyObject) == True).all()
and
DBSession.query(MyObject).filter(self.check_attributes(MyObject)).all()
Both failed to select the right objects. What am I doing wrong?
As I said in my comment, hybrid_method/hybrid_property is the appropriate pattern for your use case. It may at first seem complicated, but it's actually quite simple. The first version of the function operates exactly like a Python method or property, and the second part acts as a class method. SQLAlchemy filters work on the class to generate SQL.
This is just a useless example, but instead of therabouts your example could have a complicated calculation.
If you don't need to pass any parameters then I suggest using hybrid_property instead.
class MyObject(Model):
name = Column(String)
num = Column(Integer)
#hybrid_method
def therabouts(self, n):
return self.num > n - 5 and self.num <= n + 5
#therabouts.expression
def therabouts(cls, n):
return and_(cls.num > n - 5, cls.num <= n + 5)
#hybrid_property
def is_al(self):
return self.name.lower().startswith('al')
#is_al.expression
def is_al(cls):
return cls.name.ilike('al%')
# When used as a class method #thereabouts.expression is called
near20 = session.query(MyObject).filter(MyObject.therabouts(20)).first()
# When used as an instance, #hybrid_method is called
near20.therabouts(20) # True
near20.therabouts(22) # Maybe True
near20.therabouts(50) # False
# filter example (class)
all_als = session.query(MyObject).filter(MyObject.is_al).all()
for al in all_als:
print al.name
# output Alan, Alanzo, Albert...
# instance example (self)
bob = MyObject(name='Robert')
print bob.is_al # False
If by "use a function" you mean write the filters inside a function, you certainly can - you just need to pass the correct argument to it (the query) and use its return (the filtered query) in the proper place
Let's take an example from SQLAlchemy's tutorial:
wendy = session.query(User).filter_by(name='wendy').one()
You can move the filter(s) to a function easily:
def my_filter(query):
return query.filter_by(name='wendy')
wendy = my_filter(session.query(User)).one()
However, if by " function that checks an object for some properties and returns boolean values depending on the result" you mean a function that accepts a database record as an argument, I don't think it can be done (without subverting the whole purpose of using SQL).
--EDIT-- As doog abides points out, the hybrid extension, while not operating on database records, does something that's equivalent for many practical purposes.
Of course, some people will insist in writing something like:
all_users = session.query(User).all()
wendy= filter( lambda u:u.name=='wendy', all_users )
But, for the sake of the sanity of your fellow programmers and users, please don't do that.
I'm trying to create a way to apply a prefix to an item which would modify the item's existing stats. For example in the code below I am trying to apply the 'huge' prefix to the 'jar' item. I'd like to make the code reusable so that I could have different prefixes ('fast', 'healthy') that would modify different item stats.
Is it possible to hold the name of a class member in a variable?
If so, is there any reason I shouldn't?
If not, what alternatives are there?
class Prefix(object):
def __init__(self, word, stat, valu):
self.word = word
self.stat = stat
self.valu = valu
class Item(object):
def __init__(self, name, size):
self.name = name
self.size = size
def apply_prefix(self, prefix):
self.prefix.stat += prefix.valu # <-- Here is my issue
self.name = prefix.word + ' ' + self.name
# My hope is to make the code reusable for any stat
def print_stats(self):
print self.name, self.size
def main():
jar = Item('jar', 10)
huge_prefix = Prefix('huge', 'size', 5)
jar.apply_prefix(huge_prefix)
jar.print_stats()
You're trying to dynamically refer to some attribute. You do that by using getattr. And if you want to set the attribute, well... that's setattr :)
def apply_prefix(self, prefix):
target_attr = getattr(self,prefix.stat) #dynamically gets attr
setattr(self,prefix.stat,target_attr+prefix.valu)
As to whether this is the best coding style: it depends. There are some instances that code is made more clear by use of getattr. Since right now you only have two stats, it seems excessive to need this kind of dynamic attribute referencing, since I could easily do:
bogus_prefix = Prefix('huge','bogus',3)
Which is a valid Prefix, but throws an AttributeError when I try to apply it. That's not the most straightforward thing to debug.
However, there are bonuses to the getattr approach: if you add more stats, you don't have to change a bit (haha) of code in Prefix.
Other alternatives? There are always options in Python. :-)
The way I'd do it is to make Prefix just a dict of word:value pairs. Then apply_prefix would loop over the word keys, updating as many values as I wanted in one shot. It's a similarly dynamic approach, but a bit more scalable.
I asked a similar, yet lousy, question very late last night (Access to instance variable, but not instance method in Python) that caused a fair bit of confusion. I'd delete it if I could, but I can't.
I now can ask my question more clearly.
Background: I'm trying to build a black-jack game to learn python syntax. Each hand is an instance of the Hand class and I'm now at the point where I'm trying to allow for hands to be split. So, when it comes time for a hand to be split, I need to create two new hand instances. Given that further splits are possible, and I want to reuse the same methods for re-splitting hands. I therefore (I think) need to dynamically instantiate the Hand class.
Following is a code snippet I'm using to block out the mechanics:
import os
os.system("clear")
class Hand():
instances=[]
def __init__(self, hand_a, name):
Hand.instances.append(self)
self.name = name
self.hand_a = hand_a
def show_hand(self):
ln = len(self.hand_a)
for x in range(ln):
print self.hand_a[x]
class Creation():
def __init__(self):
pass
def create_name(self):
hil = len(Hand.instances)
new_name = 'hand_' + str(hil + 1)
return(new_name)
def new_instance(self):
new_dict = {0: 'Ace of Clubs', 1: '10 of Diamonds'}
new_hand_name = {}
new_hand_name.setdefault(self.create_name(), None)
print new_hand_name
new_hand_name[0] = Hand(new_dict, self.create_name())
print new_hand_name[0]
hand = Hand("blah", 'hand')
hand_z = Hand("blah_z", 'hand_z')
creation = Creation()
creation.new_instance()
here is the output:
{'hand_3': None}
<__main__.Hand instance at 0x10e0f06c8>
With regard to the instance created by the following statement:
new_hand_name[0] = Hand(new_dict, self.create_name)
Is new_hand_name[0] new the variable that refers to the instance?
Or, is hand_3 the variable?
i.e. when calling an instance method, can I use hand_3.show_hand()?
First, to answer your questions: new_hand_name[0] is the variable that refers to the instance- more specifically, it is the value in the new_hand_name dictionary accessed by the key 0. The new_hand_name dictionary, if you printed it, would look like:
{'hand_3': None, 0: <__main__.Hand instance at 0x10e0f06c8>}
Adding the value of "hand_3" to the dictionary is unnecessary, but for that matter, so is the dictionary.
What you really want to do has nothing to do with dynamic instantiation of new classes, which has nothing to do with your problem. The problem is that a Hand might represent a single list of cards, but might also represent a list of lists of cards, each of which have to be played separately. One great way to solve this is to make a separation between a player and a hand, and allow a player to have multiple hands. Imagine this design (I'm also leaving out a lot of the blackjack functionality, but leaving a little in to give you an idea of how to work this in with the rest of the program).
def draw_random_card():
"""
whatever function returns a new card. Might be in a Deck object, depends on
your design
"""
# some code here
class Player:
def __init__(self):
self.hands = []
def deal(self):
"""add a random hand"""
self.hands.append(Hand([draw_random_card(), draw_random_card()]))
def split(self, hand):
"""split the given hand"""
self.hands.remove(hand)
self.hands += hand.split()
class Hand:
def __init__(self, cards):
self.cards = cards
def hit(self):
"""add a random card"""
self.cards.append(draw_random_card())
def split(self):
"""split and return a pair of Hand objects"""
return [Hand(self.cards[0], draw_random_card()),
Hand(self.cards[1], draw_random_card())]
Isn't that simpler?
In response to your comment:
You can refer to any specific hand as self.hands[0] or self.hands[1] within the Players class.
If you want to keep track of a particular hand, you can just pass the hand itself around instead of passing a character string referring to that hand. Like this:
def process_hand(hand):
"""do something to a hand of cards"""
h.hit()
print h.cards()
h.hit()
h = Hand(cards)
process_hand(h)
This is important: modifications you make to the hand in the function work on the actual hand itself. Why put the extra step of passing a string that you then have to look up?
Also note that information specific to each hand, such as the bet, should probably be stored in the Hand class itself.
If you are sure you want to refer to each hand with a specific name (and again, it's not necessary in this case), you just use a dictionary with those names as keys:
self.hands = {}
self.hands["hand1"] = Hand([card1, card2])
self.hands["hand2"] = Hand([card1, card2])
print self.hands["hand1"]
But again, there is probably no good reason to do this. (And note that this is very different than instantiating a new variable "dynamically". It would be a good idea to look into how dictionaries work).