How to check all variables created by class function and use them? - python-3.x

In short; I started coding a few days ago and thought trying to make a simple text based adventure will let me face a lot of problems that I will encounter in other harder projects as well. My class init function produces items with some variables, one of which is it's equipment slot position [0-6]. I would like to unequip a slot, but the way I have it set up at the moment requires me to know which item is in that particular slot.
In english: unequip("mainhand"), mainhand has slotnumber 0. Get the info of all equipped items and check which one has the corresponding slotnumber, then remove that particular item.
(Some items have 2 slotnumbers ("althand") which means I will have to find a way to make sure I remove the right item from the list, but that is something I can do later). For now, I can't seem to figure out how to dynamically call items and do stuff with them.
PS. I am pretty sure I can do this in a way more phytonic manner and any suggestions are welcome, but regardless of this, I would still like to know how to dynamically call the function.
The code with which I try this:
def Unequip(Slotname): #Slotname is just a string, so I could say: unequip("Mainhand")
for count,i in enumerate(Item.slotname): #Item.slotname is a list of strings for slots which corresponds with Item.Slot which are the values determining the which slot is occupied.
if Slotname == Item.slotname[count]: #so when the name I put into the function equals the Item.slotname, I know which number in Item.Slot I need.
for items in Item: #Here we enter the problem (again, I understand that this code could be a lot better and would love some suggestions).
#Item is a object, but it's __init__ functions produces items, such as item1, item2 etc. I would like to check if any of these items is currently in my Item.Equipped and has the Item.Slot value I want to remove.
#I tried global(), locals() and dir(Item) but none give me what I need. I really hope this makes it clear.
if Item.Slot[count] == items.slot and items.name == Item.Equipped: #I need a susbtitute for the items variable which will represent item1, item2 or item3 etc. So I can do Item.Slot.remove(item2.slot).
Slot = Item.Slot.remove(items.slot)
Equipped = Item.Equipped.remove(items.name)
Player.stats = list(map(operator.sub,list(Player.stats),self.itemstats))
elif Item.Slot[i] == items.altslot and Items.name == items.Equipped:
pass
Full code (I tried using self etc, but it may not be super readable, my apologies), it includes a item.unequip function but this requires me to select the particular item instead of just the slot from which I want my item to be removed
Edit1: Removed all unneeded stuff per request:
import random
import operator
class Item:
Equipped = []
Slot = []
Inventory = []
num_of_items = 0
statnames = ["Strength", "Agility", "Dexterity", "Wisdom", "Constitution", "Intelligence"]
slotname = ["MainHand","Offhand","Head", "Necklace","Chest","Legs", "Cape" ]
def __init__(self, name, itemstats, slot, altslot = None, atk = None, Def = None):
self.itemstats = itemstats #itemstats in order: S, A, D, W, C, I
self.name = name
Item.num_of_items += 1
self.slot = slot
self.altslot = altslot
if atk != None and atk != 0:
self.atk = atk
if Def != None and Def != 0:
self.Def = Def
def Unequip(Slotname):
for count,i in enumerate(Item.slotname):
if Slotname == Item.slotname[count]:
for items in dir(Item):
if Item.Slot[count] == items.slot and items.name == Item.Equipped:
Slot = Item.Slot.remove(items.slot)
Equipped = Item.Eqiupped.remove(items.name)
Player.stats = list(map(operator.sub,list(Player.stats),self.itemstats))
elif Item.Slot[i] == items.altslot and Items.name == items.Equipped:
pass
class Player:
stats= [8,8,8,8,8,8]
item1 = Item("Sword of damaocles",[5, 1, 0,1,2,-2],0,1,20)
item2 = Item("Helmet of steel",[9,9,9,9,9,9],2,None,0,20)

Related

How can I change values using the same object?

So I will have to finish a half-done code to get the desired output.
the half-done code goes as follows AND I AM NOT ALLOWED TO CHANGE THIS CODE:
class Wadiya():
def __init__(self):
self.name = 'Aladeen'
self.designation = 'President Prime Minister Admiral General'
self.num_of_wife = 100
self.dictator = True
the desired output goes as follows:
Part 1:
Name of President: Aladeen
Designation: President Prime Minister Admiral General
Number of wife: 100
Is he/she a dictator: True
Part 2:
Name of President: Donald Trump
Designation: President
Number of wife: 1
Is he/she a dictator: False
Now to get this output, I will have to use the same object which is wadiya in this case to change the values of the instance variables. Then print if it affected the previous values of Part 1. If it did, I'll have to print 'Previous information lost' otherwise I'll have to print 'No, changing had no effect in previous values.'
Now my question is, how can I change the values of the instance variables using the same object? This is what I've done, but I don't think this what the question has asked me to do. What do you think? Am I on the right track? Here's my approach:
class Wadiya():
def __init__(self):
self.name = 'Aladeen'
self.designation = 'President Prime Minister Admiral General'
self.num_of_wife = 100
self.dictator = True
def my_method(self):
print('Name of the President:', self.name)
print('Designation:', self.designation)
print('Number of wife:', self.num_of_wife)
print('Is he/she a dictator:', self.dictator)
def change_values(self, name, designation, num_of_wife, dictator):
self.name = name
self.designation = designation
self.num_of_wife = num_of_wife
self.dictator = dictator
print('Part 1:')
wadiya = Wadiya()
wadiya.my_method()
print('Part 2:')
wadiya = Wadiya()
wadiya.change_values('Donald Trump', 'President', 1, False)
wadiya.my_method()
Question is a bit ambiguous why would you want to change all values of an instance. If you want you can reassign new instance to same variable just pass arguments to init instead of change_method
if you want default values to class then you don't need to do init and then change values.
def __init__(self, name: str = None): # None is default value
self.name: str = name if name else 'Aladeen'
For some reason if you want to change values of instanced objects then do
wadiya.name = 'Donald'
what you are doing will work, but generally not suggested

How to print class variables in a list

So I am very new to coding and started with python, I am trying to build a class in a program that puts together a DnD party by randomising their attributes. So far I can get the program to initialise instances of the party members and just give the user a prompt on how many of the hero's to choose from they would like in their party. My issue is that after setting the lists up and getting everything in place. I am unable to print any of the attributes of the individual heros. Regardless of whether I am calling them from within the lists or if I am directly trying to print them. I have tried using __str__ to create strings of the attributes but I am clearly missing something. Any help would be greatly appreciated.
import random
class Party:
def __init__(self, name="", race="", alignment="", class_=""):
self.name = name
while name == "":
name = random.choice(names)
# print(name)
self.race = race
while race == "":
race = random.choice(races)
# print(race)
self.alignment = alignment
while alignment == "":
alignment = random.choice(alignments)
# print(alignment)
self.class_ = class_
while class_ == "":
class_ = random.choice(classes)
# print(class_)
def character_stats(self):
return "{} - {} - {} - {}".format(self.name, self.race, self.class_, self.alignment)
Each attribute pulls a random value from a list. My format statement is the latest attempt to get the values of the attributes to print rather than the object/attributes instead.
I apologise if any of the terminology is wrong, very very new to this
You are not assigning anything else but the input, (in this case being an empty string "" to the attribuytes. In your minimal example you have this constructor:
class Party:
def __init__(self, name=""):
self.name = name
while name == "":
name = random.choice(names)
After you randomly assign a new name from names, you should assign it to self, otherwise the local variable just goes out of scope when the __init__ method finishes. This code snippet should work:
class Party:
def __init__(self, name=""):
while name == "":
name = random.choice(names)
# Now we assign the local variable as
# an attribute
self.name = name

How to implement python dictionaries into code to do the same job as list functions

I need to be able to implement dictionaries into this code. Not all needs to be changed just were i can change it and it still does the same job.
In a test file I have a list of three strings (1, once),(2,twice).(2, twice).
I'm guessing the number will represent the value.
This code passes the tests but I am struggling to understand how I can use dictionaries to make it do the same job.
If any one can help it'll be grateful.
The current is:
The list items are in a test file elsewhere.
class Bag:
def __init__(self):
"""Create a new empty bag."""
self.items = []
def add(self, item):
"""Add one copy of item to the bag. Multiple copies are allowed."""
self.items.append(item)
def count(self, item):
"""Return the number of copies of item in the bag.
Return zero if the item doesn't occur in the bag.
"""
counter = 0
for an_item in self.items:
if an_item == item:
counter += 1
return counter
def clear(self, item):
"""Remove all copies of item from the bag.
Do nothing if the item doesn't occur in the bag.
"""
index = 0
while index < len(self.items):
if self.items[index] == item:
self.items.pop(index)
else:
index += 1
def size(self):
"""Return the total number of copies of all items in the bag."""
return len(self.items)
def ordered(self):
"""Return the items by decreasing number of copies.
Return a list of (count, item) pairs.
"""
result = set()
for item in self.items:
result.add((self.count(item), item))
return sorted(result, reverse=True)
I have been scratching my head over it for a while now. I can only use these also for dictionaries.
Items[key] = value
len(items)
dict()
items[key]
key in items
Del items[key]
Thank you
Start with the simplest possible problem. You have an empty bag:
self.items = {}
and now a caller is trying to add an item, with bag.add('twice').
Where shall we put the item?
Well, we're going to need some unique index.
Hmmm, different every time, different every time, what changes with each .add()?
Right, that's it, use the length!
n = len(self.items)
self.items[n] = new_item
So items[0] = 'twice'.
Now, does this still work after a 2nd call?
Yes. items[1] = 'twice'.
Following this approach you should be able to refactor the other methods to use the new scheme.
Use unit tests, or debug statements like print('after clear() items is: ', self.items), to help you figure out if the Right Thing happened.

Python 2.7 Is there an equivalent method to locals formatting when adding class attributes into a string?

I have a class that has a number of attributes and within that class I have a function that combines those attributes into a string.
The string is quite long so for visual purposes, I would like to see exactly which variable is inserted where. The ideal solution is to use "This is my %(self.var_name)s" %locals() however the solution only works if I redefine my variable first. For example see the example script:
class Shopping(object):
def __init__(self):
self.n_apples = 4
self.n_pears = 5
self.n_grapefruit =7
def generate_list_from_self(self):
self.shoppingList = """
My Shopping List
apples = %(self.n_apples)s
pears = %(self.n_pears)s
grapefruits = %(self.n_grapefruit)s
""" %locals()
def generate_list_redefine_variables(self):
n_apples = self.n_apples
n_pears = self.n_pears
n_grapefruit = self.n_grapefruit
self.shoppingList = """
My Shopping List
apples = %(n_apples)s
pears = %(n_pears)s
grapefruits = %(n_grapefruit)s
""" %locals()
shopping = Shopping()
# First method
shopping.generate_list_from_self()
# Second method
shopping.generate_list_redefine_variables()
The ideal solution would be to use the generate_from_self() method but the variables are not picked up by %locals(). Instead I am using the second approach and redefining the variables locally before inserting them into the string. This seems cumbersome and I am wondering if there is a better way of achieving this?
It is crucial that I am able to see where the variable is inserted into the string as the string I am working with gets very large.
First the simple approach will be changing the first method to:
def generate_list_from_self(self):
self.shoppingList = """
My Shopping List
apples = %(n_apples)s
pears = %(n_pears)s
grapefruits = %(n_grapefruit)s
""" %vars(self)
here i used the vars method
in general it's common to use __str__(self) for this approach ( converting your class to string) but since there is an init of self.shoppingList i am not sure this is the right approach for you. but i'll reference you anyway to an implementation of this:
class Shopping(object):
def __init__(self):
self.n_apples = 4
self.n_pears = 5
self.n_grapefruit =7
def __str__(self):
self.shoppingList ="""
My Shopping List
apples = %(n_apples)s
pears = %(n_pears)s
grapefruits = %(n_grapefruit)s
""" %vars(self)
return self.shoppingList
shopping = Shopping()
str(shopping) # calls your class's __str__(self) method
and lastly to generailse this class to contain all shopping needed you can use a dict and return (key, value) pairs so you don't have to define a variable for every product.

How to find in a collection?

i have the following variable and collection
def currentProduct = "ITEM1"
def currentPresentation = "Crema"
def curentMeasure = "1ml"
def items = [[product:"ITEM1", presentation:"Crema", measure:"1ml", quantity:5, total:77.50], [product:"ITEM1", presentation:"Spray", measure:"Habracadabra", quantity:9, total:158.40]]
I need to get the quantity value in a map that its product, its presentation and its measure are equal to variable values, hopefully you can help me
Thanks for your time
Here You go:
items.find { it.product == currentProduct && it.presentation == currentPresentation && it.measure == curentMeasure}?.quantity
Another simpler approach will be as below:
def currentProductDetails = [
product:"ITEM1", presentation:"Crema", measure:"1ml"
]
items.find { !( currentProductDetails - it ) }?.quantity
// in case of multiple products
items.findAll { !( currentProductDetails - it ) }*.quantity
You can tailor currentProductDetails with whichever key value pair you have in hand for the current product instead of maintaining each variable separately.
Above logic is inspired from this question which is explained in details in this blog.
Dispite good #Opal's answer i will list here some additional possibilities:
Passing partial item map
If your item is [product:"ITEM1", presentation:"Crema", measure:"1ml", quantity:5, total:77.50]
and you want to search by some specified values of item, you can just pass submap of the item.
e.g.
def item = [product:currentProduct, presentation:currentPresentation, measure:curentMeasure]
def firstQuantity = items.find {it.subMap(item.keySet())==item}.quantity
That way allows you to be independent of item's keys.
Searching all quantities and suming them
Maybe in some cases you would like to have some of found quantities. You need then to use findAll() method.
def all = items.findAll { it.product == currentProduct && it.presentation == currentPresentation && it.measure == curentMeasure}.quantity.sum()
Use grep :
items.grep{it.product==currentProduct && it.presentation==currentPresentation && it.measure==curentMeasure}.collect{it.quantity}
FIDDLE

Resources