I'm trying to print these car_object[objectname] objects, but not sure how to do it....
I also have a Cars class. When I do print(car_object[objectname]) I get ObjectmeA160
<__main__.Cars object at 0x027FB970>. what am I doing wrong?
def __iter__(self):
car_object = {}
cursor = self._db.execute('SELECT IDENT, MAKE, MODEL, DISPLACEMENT,
POWER, LUXURY FROM CARS')
for row in cursor:
car_object = {}
objectname = 'Object'+str(row['IDENT'])
car_object[objectname] = Cars(ident = row['IDENT'], make = row['MAKE'],
model = row['MODEL'], disp = row['DISPLACEMENT'], power = row['POWER'], luxury = row['LUXURY'])
print(car_object[objectname])
yield dict(row)
class Cars:
def __init__(self, **kwargs):
self.variables = kwargs
def set_Variable(self, k, v):
self.variables[k] = v
def get_Variable(self, k):
return self.variables.get(k, None)
The <__main__.Cars object at 0x027FB970> is the standard string for custom objects that do not implement their own .__str__() hook. You can customize it by implementing that method:
class Cars:
# ....
def __str__(self):
return 'Car instance with variables: {!r}'.format(self.variables)
Related
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 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 in designing one "jigsaw puzzle" like tool to manage different water pipe like parts combination for fun.
I have different single parts type with different purpose(cooler, heater, purifier...)
Those parts with different interfaces size can be connected with each other (1/4 inch. 1/6 inch ....)
I want those parts can be stored in database and can be combined into a total new parts combination(randomly or purposely), but still can be considering as a function-able part.
Here is the initial thinking
class MetaInfo():
def __init__(self, name, intype,outtype,shape,serialno):
this.name = name
this.intype = intype
this.outtype = outtype
this.shape = shape
this.sn = serialno
def parts():
def __init__(self, meta):
this.meta = meta
def linkwith(self, part):
if part.meta.shape == this.meta.shape:
# make it simple, logical here is just same shape can be connected each other
return ??? # a new parts combination
else:
raise Error
m1 = MetaInfo("cooler", "hotwater", "coldwater", "1/4 inch round", "SN:11111" )
m2 = MetaInfo("heater", "coldwater", "hotwater", "1/4 inch round", "SN:22222" )
m3 = MetaInfo("purifier", "coldwater", "hotwater", "1/6 inch round", "SN:33333" )
a = parts(m1)
b = parts(m2)
c = parts(m3)
Here is what I need your help:
how to save m1, m2, m3 as a list which can persistent in a human readable database, next time only change that database itself I can add meta?
how to chain different parts as a new combination? Such as
e = a.linkwith(b)
d = c.linkwith(a)
and store it in that database as well?
can I make a long chain, make a new parts instance , such as
f = c.linkwith(a,b,d,e)
and findout easily which part is incapable to link in this chain, here part c with different size?
Many thanks.
I got bored. It's very rough but it works. If you take this far enough, you will want to use a database; but I understand wanting to use a human readable format.
from copy import copy
import csv
class Part_Base(object):
pass
class MultiPart_Base(list):
pass
class part_meta(type):
part_names = {}
parts = []
def __init__(cls, cls_name, cls_bases, cls_dict):
super(part_meta, cls).__init__(cls_name, cls_bases, cls_dict)
if(not Part_Base in cls_bases):
part_meta.part_names[cls_name] = cls
def __call__(self, *args, **kwargs):
name = kwargs.get("name", "")
if(part_meta.part_names.has_key(name) and not (self is part_meta.part_names[name])):
obj = part_meta.part_names[name].__call__(*args, **kwargs)
else:
obj = None
if(not part_meta.part_names.has_key(self.__name__)):
new_class = part_meta(name, (Generic_Part,), {})
globals()[name] = new_class
obj = new_class(*args, **kwargs)
else:
obj = super(part_meta, self).__call__(*args, **kwargs)
if not obj in part_meta.parts:
part_meta.parts.append(obj)
return obj
#classmethod
def save(cls):
all_fields = list(reduce(lambda x, y: x | set(y.fields), cls.parts, set([])))
with open("parts.csv", "w") as file_h:
writer = csv.DictWriter\
(
file_h,
all_fields,
restval = "",
extrasaction = "ignore",
dialect = "excel",
lineterminator = "\n",
)
writer.writeheader()
for part in cls.parts:
writer.writerow({field : getattr(part, field) for field in part.fields})
#classmethod
def load(cls):
with open("parts.csv", "r") as file_h:
reader = csv.DictReader(file_h)
for row in reader:
Part(**row)
class Part(Part_Base):
__metaclass__ = part_meta
fields = []
def __init__(self, **kwargs):
for name, value in kwargs.items():
setattr(self, name, value)
self.fields += kwargs.keys()
def __repr__(self):
return "<%s>" % self.description
#property
def description(self):
return "%s: %s %s %s %s" % (self.name, self.intype, self.outtype, self.shape, self.serialno)
def linkwith(self, *parts):
return Generic_MultiPart(self, *parts)
class Generic_Part(Part):
def __init__(self, **kwargs):
kwargs["name"] = self.__class__.__name__
super(Generic_Part, self).__init__(**kwargs)
class Generic_MultiPart(MultiPart_Base):
def __init__(self, *parts):
super(Generic_MultiPart, self).__init__()
if len(parts) >= 2:
self.shape = parts[0].shape
self.linkwith(*parts)
else:
raise ValueError("Not enough parts")
def __repr__(self):
return "<MultiPart: %s>" % super(Generic_MultiPart, self).__repr__()
def linkwith(self, *parts):
for part in parts:
if part.shape == self.shape:
if isinstance(part, Part):
self.append(part)
elif isinstance(part, MultiPart_Base):
self.extend(part)
else:
raise ValueError("Incompatible parts")
return self
class cooler(Generic_Part):
intype = "hotwater"
outtype = "coldwater"
fields = ["intype", "outtype"]
class heater(Generic_Part):
intype = "coldwater"
outtype = "hotwater"
fields = ["intype", "outtype"]
def make_some_parts():
some_parts = \
[
# This is actually a cooler object
# The metaclass uses the cooler class from above
# to create the object
Part
(
name = "cooler",
shape = "1/4 inch round",
serialno = "SN:11111"
),
# Using the heater class directly
heater
(
shape = "1/4 inch round",
serialno = "SN:22222"
),
Part
(
name = "purifier",
intype = "coldwater",
outtype = "hotwater",
shape = "1/6 inch round",
serialno = "SN:33333"
),
Part
(
name = "carbon_filter",
intype = "coldwater",
outtype = "coldwater",
shape = "1/4 inch round",
serialno = "SN:33333"
)
]
useless_part = some_parts[0].linkwith(some_parts[1])
print useless_part
filter_part = copy(useless_part).linkwith(some_parts[3])
print filter_part
part_meta.save()
def load_some_parts():
part_meta.load()
print part_meta.parts
You can manually edit parts.csv (in Excel or other) and it will make the parts described.
The save/restore functionality hasn't been extended to MultiParts; you can do that.
I have a form with a ModelMultipleChoiceField to list of categories.
I would like to group categories using the Category.group field.
I thought that by changing the field.choices in the init function it will make the trick
class CategoriesField(forms.ModelMultipleChoiceField):
def __init__(self, queryset, **kwargs):
super(forms.ModelMultipleChoiceField, self).__init__(queryset, **kwargs)
self.queryset = queryset.select_related()
self.to_field_name=None
group = None
list = []
self.choices = []
for category in queryset:
if not group:
group = category.group
if group != category.group:
self.choices.append((group.title, list))
group = category.group
list = [(category.id, category.name)]
else:
list.append((category.id, category.name))
try:
self.choices.append((group.title, list))
except:
pass
But the ModelChoiceIterator still erase the self.choices info that are set in the __init__ function.
How can I do that the right way ?
Actually it is working like I just explain but dont forget that part :
class ProfilForm(ModelForm):
categories = CategoriesField(queryset=Category.objects.all().order_by('group'), label=_(u'Catégories'))
Yor code worked for me, thank you! It is also possible to use with models.ManyToManyField which may be interesting for others, too:
from django.db import models
class CustomManyToManyField(models.ManyToManyField):
def formfield(self, *args, **kwargs):
kwargs["form_class"] = CategoriesField
return super().formfield(**kwargs)
I had the same caching error, and also fixed it by putting the whole choice update in an iterator:
class CustomModelChoiceIterator(forms.models.ModelChoiceIterator):
def __iter__(self):
group = ""
subgroup = []
for category in self.queryset:
if not group:
group = category.group
if group != category.group:
yield (group.title, subgroup)
group = category.group
subgroup = [(category.id, category.name)]
else:
subgroup.append((category.id, category.name))
yield (group.title, subgroup)
class CategoriesField(forms.ModelMultipleChoiceField):
iterator = CustomModelChoiceIterator
I found this question/answer helpful but changed the code a lot. The problem with the above code is that it only generates the list once and then it's cached (the queryset is only used once). My code is for an "Article" objects that's ordered by "profile" (aka author), but anyone should be able to modify it for their use. It uses a new queryset each time so it's updated without a restart (unless you pass cache_choices=True to ArticleMultipleChoiceField and then it's cached).
class ArticleChoiceIterator(forms.models.ModelChoiceIterator):
def __iter__(self):
if self.field.empty_label is not None:
yield ("", self.field.empty_label)
if self.field.cache_choices:
if self.field.choice_cache is None:
last_profile = None
self.field.choice_cache = []
for article in self.queryset.all():
if last_profile != article.profile:
last_profile = article.profile
article_list = []
self.field.choice_cache.append((article.profile.name, article_list))
article_list.append(self.choice(article))
for choice in self.field.choice_cache:
yield choice
else:
last_profile = None
article_choices = []
for article in self.queryset.all():
if last_profile != article.profile:
if article_choices:
yield (getattr(last_profile, 'name', ''), article_choices)
last_profile = article.profile
article_choices = []
article_choices.append(self.choice(article))
if article_choices:
yield (getattr(last_profile, 'name', ''), article_choices)
class ArticleMultipleChoiceField(forms.ModelMultipleChoiceField):
# make sure queryset is ordered by profile first!
def __init__(self, queryset, **kwargs):
super(ArticleMultipleChoiceField, self).__init__(queryset, **kwargs)
self.queryset = queryset.select_related('profile')
self._choices = ArticleChoiceIterator(self)
class PackageForm(forms.ModelForm):
articles = ArticleMultipleChoiceField(
queryset=Article.objects.order_by('profile__name', 'title')
)
In 2022 try:
class GroupedModelChoiceIterator(ModelChoiceIterator):
def __init__(self, field, groupby):
self.groupby = groupby
super().__init__(field)
def __iter__(self):
if self.field.empty_label is not None:
yield ("", self.field.empty_label)
queryset = self.queryset
# Can't use iterator() when queryset uses prefetch_related()
if not queryset._prefetch_related_lookups:
queryset = queryset.iterator()
for group, objs in groupby(queryset, self.groupby):
yield (group, [self.choice(obj) for obj in objs])
class GroupedModelMultipleChoiceField(ModelMultipleChoiceField):
def __init__(self, *args, choices_groupby, **kwargs):
if isinstance(choices_groupby, str):
choices_groupby = attrgetter(choices_groupby)
elif not callable(choices_groupby):
raise TypeError('choices_groupby must either be a str or a callable accepting a single argument')
self.iterator = partial(GroupedModelChoiceIterator, groupby=choices_groupby)
super().__init__(*args, **kwargs)