Python is my first language, and I am very new to it, so the answer may be very clear, but after many hours looking and experimenting, I am not sure what is causing the problem.
An overview of the module:
The DicePool module is meant to manage collections of "dice", stored as dictionary items. Each dictionary key (herein poolKey) has a list containing information about one "type" of dice, most importantly, a tuple describing its faces and an integer representing the quantity of "dice" type 'x' in the "pool."
My specific question regards the Transfer method, which used to be two methods (send and receive, basically), but which I thought I could combine into one method. When the test code at the bottom runs, I'd like it to leave dp.dictPool[poolKey][1] == 0 and dp2.dictPool[poolKey][1] == 2. But in every attempt I've made, the values come out the same. Sorry I can't categorize this question better . . . I don't really know what the problem is.
Anyway, one half of the Transfer method is supposed to run for the "sender" instance, and one half is supposed to run for the "receiver" instance.
import random
class DicePool(object):
def __init__(self):
self.dictPool = {}
def AddDice(self, poolKey, faces = 6, quant = 1, color = "white"):
'''faces must be int or items 'a,b,c'; count must be int or def to 1'''
try: #if count is not an integer, it defaults to 1
quant = int(quant)
except:
print("Quant is not an integer, defaulting to 1")
quant = 1
try: #if faces is can be int, a list is built of numbers 1 to faces
faces = int(faces)
if faces < 2: #a 1 or 0-sided die breaks the program
faces = 2
tempList = []
for i in range(1, faces+1):
tempList.append(i)
faces = tempList
except: #if faces is not an integer, it is split into list items by ","
faces = faces.split(",")
if poolKey in self.dictPool.keys(): #if the key already exists in pool
self.dictPool[poolKey][1] += quant #add to the quantity,
else: #if the key does not already exist, set all attributes
self.dictPool[poolKey] = [faces, quant, color]
def Transfer(self, poolKey, targetPool, sendQuant, senderPool = None):
'''targetPool must be DicePool instance'''
if targetPool:
self.dictPool[poolKey][1] -= sendQuant
targetPool.Transfer(poolKey, None, sendQuant, self)
else:
try:
self.dictPool[poolKey][1] -= sendQuant
except:
self.dictPool[poolKey] = senderPool.dictPool[poolKey]
self.dictPool[poolKey][1] = sendQuant
dp = DicePool()
dp2 = DicePool()
dp.AddDice("d6")
dp.AddDice("d6")
dp.Transfer("d6",dp2,2)
print(dp.dictPool,dp2.dictPool)
The problem is in this line:
self.dictPool[poolKey] = senderPool.dictPool[poolKey]
The values in your dictPools are lists. Here, you set one object's dictPool value to the same list as in the other one. Not a copy of the list, but the same list. So later if you add or subtract from that list, it will affect the other as well, because they are sharing one list object.
Try doing self.dictPool[poolKey] = senderPool.dictPool[poolKey][:]. The [:] grabs the contents of the list rather than the list object iself.
In both parts of the if/else in Transfer you're subtracting the quantity. Don't you want to subtract it in one case but add it in the other?
Is else: try: self.dictPool[poolKey][1] -= sendQuant supposed to be += sendQuant instead?
Might be a semantic issue, not a Python syntax issue.
Here is a version of the Transfer() method that seems to work as intended (more or less), although it's very clumsy looking:
def Transfer(self, poolKey, targetPool, sendQuant, senderPool = None):
'''targetPool must be DicePool instance'''
if isinstance(targetPool, DicePool):
#valid target, so subtract dice here, then call Transfer on target
temp = self.dictPool[poolKey][1:2][0] - sendQuant
print("sent",sendQuant,"leaving",temp)
targetPool.Transfer(poolKey, "Receiver", sendQuant, self)
elif targetPool == "Receiver":
#this executes if a DicePool is named as the targetPool of Transfer
if poolKey in self.dictPool.keys():
self.dictPool[poolKey][1:2][0] += sendQuant
else:
self.dictPool[poolKey] = senderPool.dictPool[poolKey]
self.dictPool[poolKey][1:2] = [sendQuant]
print("now have",self.dictPool[poolKey][1:2][0])
pass
else:
print("Not a valid targetPool, apparently")
Related
I'm adding a function to a class to output the item with the lowest price but what I'm getting are all the prices. See photo and code. What am I missing on the code?
def get_low_price(self):
self.get_total_toys()
#To check if toybox is empty or not
if self.total > 0:
msg = f'The toy box contains {self.total} toys\n'
for a_toy in self.all_toys:
self.get_total_cost()
msg += f'A {(a_toy.colour).lower()} {a_toy.name} which cost ${a_toy.price:.2f}\n'
for i in [a_toy.price]:
i = ([i])
print(min(i))
return f'{msg}Total cost: ${self.cost_total:.2f}'
This inner loop isn't doing anything useful:
for i in [a_toy.price]:
i = ([i])
print(min(i))
Here a_toy is already just a single toy. Looping over a new list containing only its price doesn't accomplish anything you could get just by accessing a_toy.price directly, and rebinding the loop variable i to another new list (in extraneous parentheses) doesn't add anything.
I think you want to move all of the min-finding logic outside of the earlier loop, unless you want to compare prices yourself. Instead, you can use just one min call, outside of the loop:
for a_toy in self.all_toys: # don't include the stuff below in this loop
...
cheapest = min(self.all_toys, key=lambda t: t.price) # find cheapest
# do something down here with cheapest, or cheapest.name, maybe
I didn't understand what exactly you are trying to do using the for loop in that method. If you are thinking that i = ([i]) is going to append price to a list then it's wrong. Use the below logic and rewrite your method. It will work.
toys = {"doll": 5, "hulk": 10, "teddy": 15}
cheapest_toy_name = ""
cheapest_toy_price = float("inf")
for k, v in toys.items():
if cheapest_toy_price > v:
cheapest_toy_price = v
cheapest_toy_name = k
print(cheapest_toy_name)
I am creating a leaderboard creating system, where it checks if the Name is already in the Database, if not it adds it, and if it is it replaces the name and score.
import csv
winner =["Player", 100]
def leaderboardsave(winner):
fileCSV = open('scores.csv')
dataCSV = csv.reader(fileCSV)
playersScores = list(dataCSV)
winnerName = winner[0]
winner_index = playersScores.find(winnerName)
if winner_index > -1:
playersScores[winner_index] = winner
else:
playersScores.append(winner)
leaderboardsave(winner)
The CSV is saved like this:
Player, 20
Player2, 40
Player3, 30
Player4, 60
whenever I run
winner_index = playersScores.find(winnerName)
it returns "'list' object has no attribute 'find'"
Any other ways to find where the item is in the list? When i tried using .index, it wouldnt find it, i assume as it is looking for a list, not a single string?
You are getting that error because playerScores is a list object and a list object doesn't have a find function.
You can traverse a list to find a value by looping:
winner_index = [index for index, value in enumerate(playerScores) if value == winnerName]
I'm trying to check if an object has a skinCluster on it. My code is pretty basic. Here's an example:
cmds.select(d=True)
joint = cmds.joint()
skinnedSphere = cmds.polySphere(r=2)
notSkinnedSphere = cmds.polySphere(r=2)
skinTestList = [skinnedSphere, notSkinnedSphere]
# Bind the joint chain that contains joint1 to pPlane1
# and assign a dropoff of 4.5 to all the joints
#
cmds.skinCluster( joint, skinnedSphere, dr=4.5)
for obj in skinTestList:
objHist = cmds.listHistory(obj, pdo=True)
skinCluster = cmds.ls(objHist, type="skinCluster")
if skinCluster == "":
print(obj + " has NO skinCluster, skipping.")
else:
print obj, skinCluster
#cmds.select(obj, d=True)
My issue is that even if it can't find a skincluster, it still prints out the "obj, skincluster" rather than the error that it can't find a skinCluster.
I thought a skinCluster returns a string. So if the string is empty, it should print out the error rather than "obj, skincluster".
Any help would be appreciated!
This is a classic Maya issue -- the problem is that Maya frequently wants to give you lists, not single items, even when you know the result ought to be a single item. This means you end up writing a bunch of code to either get one item from a one-item list or to avoid errors that come from trying to get an index into an empty list.
You've got the basics, it's the == "" which is messing you up:
for obj in skinTestList:
objHist = cmds.listHistory(obj, pdo=True)
skinCluster = cmds.ls(objHist, type="skinCluster") or [None]
cluster = skinCluster[0]
print obj, cluster
The or [None] guarantees that you'll always get a list with something in it so it's safe to use the [0] to get the single value. None is a good return value here because (as pointed out in the comments) you can if cluster: and skip empty values.
I have written something that works, but I am 100% sure that there is an even more efficient and faster way of doing what I did.
The code that I have written, essentially uses OpenBayes' library and creates a network with its nodes, relationships between nodes, and the probabilities and distributions associated with each of the nodes. Now, I was creating a GET request using Flask, in order to process the conditional probabilities by simply sending the request.
I will send some evidence (given values), and set the node in which I want its probability (observed value). Mathematically it looks like this:
Observed Value = O and Evidence = En, where n > 1
P( O | E1, E2, ..., En)
My final goal would be to have a client/server ping the server hosting this code(with the right parameters) and constantly give me the final values of the observed probability, given the evidence (which could be 1 or more values). The code I have written so far for the GET request portion is:
#app.route('/evidence/evidence=<evidence>&observed=<obv>', methods=['GET'])
def get_evidence(evidence, obv):
# Take <evidence> and <obv> split them up. For example:
# 'cloudy1rain0sprinkler1' to 'cloudy1', 'rain0' and 'sprinkler1', all in a nice list.
analyzeEvidence, observedNode = evidence.upper().strip(), obv.upper().strip()
string, count, newCount, listOfEvidence = "", 0, 0, {}
counter = sum(character.isdigit() for character in analyzeEvidence)
# This portion is to set up all the evidences.
for y in xrange(0, counter):
string, newCount = "", count
for x in xrange(newCount, len(analyzeEvidence)):
count += 1
if analyzeEvidence[x].isalpha() == True:
string += str(analyzeEvidence[x])
elif analyzeEvidence[x].isdigit() == True and string in allNodes:
if int(analyzeEvidence[x]) == 1 or int(analyzeEvidence[x]) == 0:
listOfEvidence[string] = int(analyzeEvidence[x])
break
else: abort(400)
break
else: abort(400)
net.SetObs(listOfEvidence) # This would set the evidence like this: {"CLOUDY": 1, "RAIN":0}
# This portion is to set up one single observed value
string = ""
for x in xrange(0, len(observedNode)):
if observedNode[x].isalpha() == True:
string += str(observedNode[x])
if string == "WETGRASS":
string = "WET GRASS"
elif observedNode[x].isdigit() == True and string in allNodes:
if int(observedNode[x]) == 1 or int(observedNode[x]) == 0:
observedValue = int(observedNode[x])
observedNode = string
break
else: abort(400)
else: abort(400)
return str(net.Marginalise(observedNode)[observedValue]) # Output returned is the value like: 0.7452
Given my code, is there any way to optimize it? Also, Is there a better way of passing these parameters that doesn't take so many lines like my code does? I was planning on setting fixed key parameters, but because my number of evidence can change per request, I thought this would be one way in doing so.
You can easily split your evidence input into a list of strings with this:
import re
# 'cloudy1rain0sprinkler1' => ['cloudy1', 'rain0' and 'sprinkler1'].
evidence_dict = {}
input_evidence = 'cloudy1rain0sprinkler1'
# looks for a sequence of alphabets followed by any number of digits
evidence_list = re.findall('([a-z]+\d+)', input_evidence.lower())
for evidence in evidence_list:
name, val, _ = re.split('(\d+)', evidence)
if name in allNodes:
evidence_dict[name] = val
# evidence_dict = {'cloudy': 1, 'rain': 0, 'sprinkler': 1}
You should be able to do something similar with the observations.
I would suggest you use an HTTP POST. That way you can send a JSON object which will already have the separation of variable names and values done for you, all you'll have to do is check that the variable names sent are valid in allNodes. It will also allow your variable list to grow somewhat arbitrarily.
I have a project to create a circular array class, and the language I will be using is python. I am new to classes in python, but after reading through some webpages and chapters in books I think I have an understanding of how they work. However I need help, so I figured I would come to the wonderful teachers here at SO :)
Our class must be able to implement several operations; insert at front, insert at back, insert at index, remove from front, remove from back, remove from index.
I have started coding but am running into some problems, and I am not 100% sure if my syntax is even right.
Here is what I have so far:
class circular:
def __init__(self):
self.store = []
self.capacity = len(self.store)
self.size = 0
self.startIndex = 0
self.endIndex = 0
def decrementIndex(self):
index = index - 1
if index < 0:
self.store = self.store + self.capacity
def incrementIndex(self):
index = index + 1
if index == self.capacity:
index = index - self.capacity
def addToBack(self, value):
self.store[self.endIndex] = value
self.endIndex = incrementIndex(self.endIndex)
self.size += 1
def addToFront(self, value):
if self.size == 0:
addToBack(self, value)
else:
self.startIndex = decrementIndex(self.startIndex)
self.store[self.startIndex] = value
self.size += 1
I stopped there to start testing some of the functions, primarily t he addTofront and addToback. Upon testing them in IDLE using c = circular() and c.addToBack(2) I get an index error...and I'm not sure why. That isn't the only problem, it's just where I have gotten stuck and need help moving forward.
I am posting here because I need help and want to learn, not because I am lazy and haven't tried researching my problem. Thanks already SO!
In __init__ you set
self.store = []
In addToBack you do
self.store[self.endIndex] = value
If this is the first operation on the circular array, and you pass 2 as the value, then that turns into
[][0] = 2
The problem should be obvious -- an empty list has no index of 0, it has no indexes at all.
You need to add the item to the list in a different way.
I'm not going to tell you exactly how as it's part of your homework to figure that out.