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
Related
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()
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.
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 am working on creating a module with a class that acts as a container for a list of another created class. Is there a way for the container class to be able to tell if any of the objects it contains has changed?
Here is an example:
class Part:
def __init__(self, size):
self.part_size = size
class Assembly:
def __init__(self, *parts):
self.parts = list(parts) # `parts` are all Part() objects
self.update()
def update(self):
self.assy_size = 0
for each in self.parts:
self.assy_size += each.part_size
def __getitem__(self, key):
return self.parts[key]
This is what I get if I try to change any of the Part properties in the Assembly:
>>>x = Part(1)
>>>y = Part(1)
>>>z = Part(1)
>>>u = Assembly(x, y, z)
>>>u.assy_size
3
>>>u[0].part_size = 4
>>>u.assy_size
3
I know that I can create additional methods that will call the update method if I replace, delete, or add Part objects to the Assembly, but is there any way to have the Assembly notified if any of the contained Part properties have changed?
The answer is in your question. Use a property.
class Part:
_size = 0
assembly = None
#property
def part_size(self):
return self._size
#part_size.setter
def part_size(self, value):
self._size = value
if self.assembly: # only notify if an Assembly is set
self.assembly.update()
def set_assembly(self, assembly):
self.assembly = assembly
def __init__(self, size):
self.part_size = size
class Assembly:
def __init__(self, *parts):
self.parts = list(parts) # `parts` are all Part() objects
for part in self.parts:
part.set_assembly(self) # reference to self needed to notify changes
self.update()
def update(self):
self.assy_size = 0
for each in self.parts:
self.assy_size += each.part_size
In this version of Assembly the constructor sets a reference on the Part to itself. This way it can update the assembly when the part_size changes. Use it as the example in your question.
>>>x = Part(1)
>>>y = Part(1)
>>>z = Part(1)
>>>u = Assembly(x, y, z)
>>>u.assy_size
3
>>>u[0].part_size = 4
>>>u.assy_size
6
If update isn't an expensive operation (in your example it isn't, but maybe in reality you have thousands of parts), you could calculate the size ad-hoc using a property:
class Assembly:
def __init__(self, *parts):
self.parts = list(parts)
#property
def assy_size(self):
result = 0
for each in self.parts:
result += each.part_size
return result
which can be accessed the same way: assembly.assy_size.
The calculation can also be simplified:
#property
def assy_size(self):
return sum(part.part_size for part in self.parts)
I am new in python, and I have small problem, I have two classes, and it wrotes this : set_gyro_angle() takes exactly 1 argument (2 given) how can I call set_gyro_angle() method from Machine method?
class Gyro(object):
"""gyroskop senzor"""
def __init__(self,gyro_start_angle = 0):
self.gyro_angle = 0
def get_gyro_angle():
return self.gyro_angle
def set_gyro_angle(angle):
self.gyro_angle = angle
return 0
class Maschine(object):
def __init__(self, state = "normal",length = 10,width = 15):
self.length = length
self.width = width
self.gyro = Gyro()
def setPoint(self,alpha):
self.gyro.set_gyro_angle(alpha)
return 0
Main:
maschine = Maschine()
maschine.setPoint()
If you want to create an instance method, you need to add an extra argument that will be a pointer to your instance. Usually it's self:
class Gyro(object):
"""gyroskop senzor"""
def __init__(self,gyro_start_angle = 0):
self.gyro_angle = 0
def get_gyro_angle(self):
return self.gyro_angle
def set_gyro_angle(self, angle):
self.gyro_angle = angle
return 0
And i think you want setPoint to be like this:
def setPoint(self, alpha):
self.gyro.set_gyro_angle(alpha)
All of your instance methods should have another parameter, self, before the others; this is the instance itself, and is passed automatically:
def set_gyro_angle(self, angle):
Alternatively, skip the setter:
self.gyro.gyro_angle = alpha
Machine.gyro.set_gyro_angle(45)
However you need to fix your code by adding the self parameter as the first parameter of your class methods.