So I have the following code:
#property
def mod_list(self) -> List[Modifier]:
mods = []
print(len(self.statuses)) #Prints 0??? Update method prints the actual number when called??? Also means it *is* getting called properly when it's getting accessed
for status in self.statuses: # I've tried calling the keys() method on the dict but that doesn't work either
print("hello") #Doesn't print, indicating that it isn't looping
mods.extend(status.mods) # Note: statuses dict uses StatusEffect objects as keys, with values being the number of turns left before that status is removed; StatusEffects all possess a 'mods' property that is initialized to '[]' and can only be made up of modifiers
return mods
I don't understand why it can't access the keys of the dict? Even if I remove the decorator and call it instead of accessing it?
Especially when this method works properly?
def update(self):
deletion = []
print(len(self.statuses)) #Prints actual number of keys????
for name in self.statuses.keys():
print(name.name, self.statuses[name]) #Prints normally whenever update is called???
if hasattr(name, "turn_effect"):
name.turn_effect(self.entity)
self.statuses[name] -= 1
if self.statuses[name] < 1:
deletion.append(name)
...
for status in deletion:
del self.statuses[status]
Why isn't it working properly? And how do I fix it?
Edit: I managed to recreate the issue below, I think it might have to do with 'deepcopy' in the spawn method since I couldn't recreate the issue from scratch until I implemented and used the spawn method.
from __future__ import annotations
from typing import Dict, List
from copy import copy, deepcopy
class Entity:
def __init__(self, name:str, **kwargs:Component):
self.name = name
self.components:Dict[str, Component] = {}
for name, component in kwargs.items():
self.add_component(name, component)
def add_component(self, name:str, component:Component):
self.components[name] = component
component.entity = self
def update(self):
for comp in self.components.values():
comp.update()
def spawn(self):
return deepcopy(self)
class Component:
__entity: Entity
#property
def entity(self) -> Entity:
return self.__entity
#entity.setter
def entity(self, entity:Entity):
if hasattr(self, "__entity") and self.__entity is not None:
self.entity.remove_component(self)
self.__entity = entity
def update(self):
"""Placeholder method for component update methods"""
class StatusList(Component):
entity: Entity
def __init__(self) -> None:
self.statuses:Dict[StatusEffect, int] = {}
def add_status(self, status:StatusEffect, turns:int=1):
self.statuses[status] = turns
def update(self):
deletion = []
print(len(self.statuses.keys()))
for name in self.statuses.keys():
print(name.name, self.statuses[name])
if hasattr(name, "turn_effect"):
name.turn_effect(self.entity)
self.statuses[name] -= 1
if self.statuses[name] < 1:
deletion.append(name)
for status in deletion:
del self.statuses[status]
#property
def mod_list(self) -> List[Modifier]:
mods = []
print(len(self.statuses))
for status in self.statuses:
print("hello")
mods.extend(status.mods)
return mods
class StatusEffect:
name:str
turn_effect: function
mods:List[Modifier] = []
def apply(self, entity:Entity, turns:int=1):
if "status_list" in entity.components.keys():
entity.components["status_list"].add_status(self.copy(), turns)
def copy(self): #I specifically defined this method in the original code in case I need to modify it in the future
return copy(self)
class StatList(Component):
entity: Entity
stat_record: List[Stat] = []
def __init__(self, **stats:Stat) -> None:
for name, stat in stats.items():
stat.stat_list = self
stat.name = name
self.stat_record.append(stat)
def get_stat(self, name:str) -> Optional[Stat]:
for stat in self.stat_record:
if name == stat.name:
return stat
def get_stat_name(self, stat:Stat) -> Optional[str]:
if stat in record:
return stat.name
class Stat:
name:str
base_value:int
def __init__(self, base:int=0):
self.base_value = base
#property
def entity(self) -> Entity:
return self.stat_list.entity
#property
def current_value(self) -> int:
value = self.base_value
for mod in self.get_modifiers():
value += mod.value
return int(value)
def get_modifiers(self):
for component in self.entity.components.values():
if hasattr(component, "mod_list"):
for mod in component.mod_list:
if mod.stat == self.name:
yield mod
class Modifier:
stat: str
value: Union[int, float]
def __init__(self, stat:str, value:Union[int, float]):
self.stat = stat
self.value = value
rage = StatusEffect()
rage.name = "Rage"
rage.turn_effect = lambda entity : print(f"{entity.name} is enraged")
rage.mods = [
Modifier("atk", 5)
]
player = Entity(
name="Player",
stat_list=StatList(atk=Stat(5)),
status_list=StatusList()
).spawn()
rage.apply(player, 10)
while True:
player.update()
player.components["stat_list"].get_stat("atk").current_value
input()
Unfortunately, using copy() in the spawn method would result in entities created that way sharing status effects, stats, etc., which really defeats the purpose of spawning new entities
Edit 2: Modified spawn method to use copy and to copy all components, have to add guard clauses now but it works.
Related
I have a class:
class AlchemicalElement:
def __init__(self, name: str):
self.name = name
I then create a class that will be used to store the AlchemicalElement objects:
class AlchemicalStorage:
def __init__(self):
self.storage_list = []
I don't understand how to write this function:
def extract(self) -> list[AlchemicalElement]:
"""Return a list of all the elements from storage and empty the storage itself."""
return []
So far I've only managed this:
def add(self, element: AlchemicalElement):
if isinstance(element, AlchemicalElement):
self.storage_list.append(element)
else:
raise TypeError()
This is what I try to achieve:
storage = AlchemicalStorage()
storage.add(AlchemicalElement('Water'))
storage.add(AlchemicalElement('Fire'))
storage.extract() # -> [<AE: Water>, <AE: Fire>]
storage.extract() # -> []
Question
How do I write the .extract() method so that when first called it returns a list of elements in the storage_list, but an empty list on any call after?
Assuming this is what you're starting with
class AlchemicalElement:
def __init__(self, name: str):
self.name = name
class AlchemicalStorage:
def __init__(self):
self.storage_list = []
def add(self, element: AlchemicalElement):
if isinstance(element, AlchemicalElement):
self.storage_list.append(element)
else:
raise TypeError()
def extract(self) -> list[AlchemicalElement]:
"""Return a list of all the elements from storage and empty the
storage itself."""
return []
if __name__ == "__main__":
storage = AlchemicalStorage()
storage.add(AlchemicalElement('Water'))
storage.add(AlchemicalElement('Fire'))
print(storage.extract()) # -> [<AE: Water>, <AE: Fire>]
print(storage.extract()) # -> []
You'll currently get output that looks like this
[]
[]
Your first question is how do I make the .extract() method exhaust the .storage_list?
We could do something like this:
def extract(self) -> list[AlchemicalElement]:
"""Return a list of all the elements from storage and empty the
storage itself."""
# copy the storage_list into out_list and then clear it
# only works once!
out_list = self.storage_list.copy()
self.storage_list.clear()
return out_list
Now if we run the script we should get the following:
[<__main__.AlchemicalElement object at 0x000001CB12CBBD00>, <__main__.AlchemicalElement object at 0x000001CB12CBBCA0>]
[]
Now maybe to answer another question, how to do I get it to return <AE: Water> instead of <__main__.AlchemicalElement object at ...>?
We can do that by adding a __repr__ method to the AlchemicalElement class
class AlchemicalElement:
def __init__(self, name: str):
self.name = name
def __repr__(self):
return f"<AE: {self.name}>"
All code together now looks like this
class AlchemicalElement:
def __init__(self, name: str):
self.name = name
def __repr__(self):
return f"<AE: {self.name}>"
class AlchemicalStorage:
def __init__(self):
self.storage_list = []
def add(self, element: AlchemicalElement):
if isinstance(element, AlchemicalElement):
self.storage_list.append(element)
else:
raise TypeError()
def extract(self) -> list[AlchemicalElement]:
"""Return a list of all the elements from storage and empty the
storage itself."""
# copy the storage_list into out_list and then clear it
# only works once!
out_list = self.storage_list.copy()
self.storage_list.clear()
return out_list
if __name__ == "__main__":
storage = AlchemicalStorage()
storage.add(AlchemicalElement('Water'))
storage.add(AlchemicalElement('Fire'))
print(storage.extract()) # -> [<AE: Water>, <AE: Fire>]
print(storage.extract()) # -> []
And output looks like how you want
[<AE: Water>, <AE: Fire>]
[]
Note:
The __repr__ method should return a printable representation of the object, most likely one of the ways possible to create this object. source
I successfully solved an algorithm question to serialize and deserialize binary tree.
class Codec:
def __init__(self):
self.i=0
def serialize(self, root):
store=[]
def preorder(node):
if not node:
store.append("N")
return
store.append(str(node.val))
preorder(node.left)
preorder(node.right)
preorder(root)
return ",".join(store)
# serialized data is passed here as "data" argument
def deserialize(self, data):
values=data.split(",")
def helper():
if values[self.i]=="N":
self.i+=1
return
root=TreeNode(int(values[self.i]))
self.i+=1
root.left=helper()
root.right=helper()
return root
return helper()
to solve the deserialize function, I created a top-level state variable self.i. Instead, I want to pass i to the helper function but I cannot figure it out. I tried to code like this with local variable:
def deserialize(self, data):
values=data.split(",")
def helper(i):
if values[i]=="N":
i+=1
return
root=TreeNode(int(values[i]))
i+=1
root.left=helper(i)
# i think issue is here.
# Because i is modified inside root.left=helper(i)
# so somehow I need to keep track of this modification
root.right=helper(i)
return root
return helper(0)
Instead of using an instance attribute (i), you could use a local variable i like you tried, but then not passing it as argument to helper, but referencing it as a nonlocal name. But I would not advise that. Instead create an iterator over the given values. Then you can call next on it to get the next value.
Once you got rid of the ugly instance attribute, you no longer need instances at all, and I wonder why you would need a class Codec at all. It you really want to keep it, then create those two functions as static methods as it doesn't make sense to ever need to create an instance of Codec:
Here is complete code with a run on a sample tree:
class TreeNode:
def __init__(self, val):
self.val = val
self.left = self.right = None
def add(self, val):
if val < self.val:
if self.left:
self.left.add(val)
else:
self.left = TreeNode(val)
else:
if self.right:
self.right.add(val)
else:
self.right = TreeNode(val)
def print(self, tab=""):
if self.right:
self.right.print(tab + " ")
print(tab, self.val)
if self.left:
self.left.print(tab + " ")
#staticmethod
def of(*values):
if values:
root = TreeNode(values[0])
for val in values[1:]:
root.add(val)
return root
class Codec:
#staticmethod
def serialize(root):
store=[]
def preorder(node):
if not node:
store.append("N")
return
store.append(str(node.val))
preorder(node.left)
preorder(node.right)
preorder(root)
return ",".join(store)
#staticmethod
def deserialize(data):
values = iter(data.split(","))
def helper():
val = next(values)
if val=="N":
return
root = TreeNode(int(val))
root.left = helper()
root.right = helper()
return root
return helper()
tree = TreeNode.of(4,2,6,1,3,5,7)
tree.print()
s = Codec.serialize(tree)
print(s)
root = Codec.deserialize(s)
root.print()
I want to list the objects by its attribute, and get it with only the attributes that is in the list.
class foo:
def __init__(self,id):
self.id=id
a=foo(0)
b=foo(1)
ids=[a.id,b.id]
can I refer to a with only having ids ?
and if it is not possible this way, how can I ?
User a dictionary:
class foo:
def __init__(self,id):
self.id=id
a=foo(0)
b=foo(1)
ids={a.id:a, b.id:b}
print(ids[0])
An example without a dictionary
NOTE: This may be better achieved using a Meta-programming in Python, and your question may seem that can have an actual real world usage when creating Python Packages, Frameworks etc.
Still, in a clumsy way it does achieve this.
import random
class foo:
def __init__(self,id):
self.id=id
def create_counter():
count = 0
def internal():
nonlocal count
count += 1
return count
return internal
counter = create_counter()
def create_id():
"""Generate random id, uses a stateles Closure to keep track of counter"""
id_ = None
name = 'class_'
id_gen = str(hex(random.randrange(1000)))
id_ = name + str(counter()) + "_" + id_gen[2:]
return id_
def change_name_ref(inst_obj):
"""Change Instance Name to Instance ID"""
inst_obj.__name__ = inst_obj.id
a = foo(create_id()) # --> Assign a radnom Id
b = foo(create_id())
c = foo('class_1_15b')
change_name_ref(a)
change_name_ref(b)
change_name_ref(c)
ids = [a, b, c]
def get_instance(inst_list, target):
for idx, id_ in enumerate(inst_list):
if id_.__name__ == target:
inst = inst_list[idx]
print(f'Here The Class instance {inst}, ID: {inst.id}')
value = get_instance(ids, 'class_1_15b')
# Here The Class instance <__main__.foo object at 0x7f6988f016d0>, ID: class_1_15b
I need help with the below code. I want to use the get_skies, get_high, and get_low method to call the set_skies, set_high, and set_low methods, respectively, and then return the value for init_skies, init_high, and init_low, respectively.
This is what I have got so far:
class WeatherForecast():
def set_skies(self, init_skies):
return init_skies
def set_high(self, init_high):
return init_high
def set_low(self, init_low):
return init_low
def get_skies(self):
self.set_skies()
def get_high(self):
self.set_high()
def get_low(self):
self.set_low()
In python attributes of class are publically accessible.
You don't need to use getter or setters for attributes unless you want to perform some kind of preprocessing or mutation of the attribute
In your case, you can try this,
class WeatherForecast():
def __init__(self, init_skies, init_low, init_high):
self._init_skies = init_skies
self._init_low = init_low
self._init_high = init_high
#property
def skies(self):
return self._init_skies
#property
def high(self):
return self._init_high
#property
def low(self):
return self._init_low
#skies.setter
def skies(self, value):
self._init_skies = value
#high.setter
def high(self, value):
self._init_high = value
#low.setter
def low(self, value):
self._init_low = value
w = WeatherForecast(1, 2, 3)
print(w.skies, w.low, w.high) # --> print the values
# Set the values
w.skies = 10
w.low = 20
w.high = 30
print(w.skies, w.low, w.high) # --> print the updated values
I am trying to solve this problem:
Imagine a (literal) stack of plates. If the stack gets too high, it
might topple. There- fore, in real life, we would likely start a new
stack when the previous stack exceeds some threshold. Implement a data
structure SetOfStacks that mimics this. SetOf- Stacks should be
composed of several stacks, and should create a new stack once the
previous one exceeds capacity. SetOfStacks.push() and
SetOfStacks.pop() should behave identically to a single stack (that
is, pop() should return the same values as it would if there were just
a single stack). Bonus: Implement a function popAt(int index) which
performs a pop operation on a specific sub-stack.
So I wrote the code:
#!/bin/env python
from types import *
class Stack:
def __init__(self):
self.items = []
self.capacity = 3
self.stackscount = 0
def create(self):
id = self.stackscount + 1
id = str(id) + "_stack"
# How to create a new instance of Stack class at runtime ?
# the __init__ must be run too.
def push(self, item):
if self.size() <= self.capacity:
self.items.append(item)
else:
self.create()
def pop(self):
return self.items.pop()
def popAt(self):
pass
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
s = Stack()
s.push(10)
How do I create a new s type object dynamically at runtime? I searched on the internet and found that using new.instance or new.classobj is the solution but when I did so my new object did not seem to have items from __init__ function. In python3, type() seems to be the answer but the docs doesn't have any examples.
You've confused yourself by referring to a "type object". In Python that means the class itself, not its instances.
To create new Stack objects, simply do what you're already doing: call the Stack class. You can append them to a list:
stacks = [Stack() for _ in range(5)]
However, as jon points out, that won't solve your problem since you haven't defined the SetOfStacks class.
You could simply use a parent-child relation : when a Stack is full, it creates a child and delegate next pushes to it. It could lead to :
class Stack:
def __init__(self, parent = None, id=None):
self.stackscount = 0
self.capacity = 3
self.items = []
self.parent = parent
self.id = id
self.child = None
def create(self):
id = self.stackscount + 1
id = str(id) + "_stack"
return Stack(self, id)
def push(self, item):
if self.size() <= self.capacity:
self.items.append(item)
else:
if self.child is None:
self.child = self.create()
self.child.push(item)
def pop(self):
if self.child is not None:
item = self.child.pop()
if len(self.child.items) == 0:
self.child = None
else:
item = self.items.pop()
return item
def popAt(self):
pass
def peek(self):
if self.child is not None:
item = self.child.peek()
else:
item = self.items[len(self.items)-1]
return item
def size(self):
l = len(self.items)
if self.child is not None:
l += self.child.size()
return l
s = Stack()
s.push(10)
popAt is still to be implemented, but I tested it and it correctly creates new stacks when pushing and empties and removes them when popping.
The implementation of popAt will require some evolutions to current pop implementation, to allow removing an intermediate stack :
def pop(self):
if self.child is not None:
item = self.child.pop()
if len(self.child.items) == 0:
self.child = self.child.child
if self.child is not None:
self.child.parent = self
else:
item = self.items.pop()
return item
def popAt(self, stacknumber):
s = self
for i in range(stacknumber):
s = s.child
if s is None:
return None
if len(s.items) == 0:
return None
item = s.items.pop()
if len(s.items) == 0 and s.parent is not None:
s.parent.child = s.child
if s.child is not None:
s.child.parent = s.parent
return item
The type() function is indeed what you are looking for. Documentation can be found here: https://docs.python.org/2/library/functions.html#type
You can call it like this:
# Bases is a tuple of parent classes to inherit
bases = Stack,
# Dict contains extra properties for the class, for example if you want to add a class variable or function
dict_ = {}
# Construct the class
YourClass = type('YourClass', bases, dict_)
# Create an instance of the class
your_instance = YourClass()
It looks like you are just looking at instance creation though:
class Stack(object):
def create(self):
id = self.stackscount + 1
id = str(id) + "_stack"
# How to create a new instance of Stack class at runtime ?
# the __init__ must be run too.
stack = Stack()