How can I update a "self" variable in Python? - python-3.x

I'm having trouble understanding how to instantiate a class, and update that instances variables. If I __init__ a series of self.x variables, then instance that class, I want to update self.x = 40. However, self.x always stays constant.
I have a feeling I'm not wrapping my head around the class variable, init variable, and instanced class variables. I can always access them, I just can't seem to change them. I have coded an example of what I am trying to do.
class Engine(object):
def __init__(self, board):
self.board = board
def play_game(self):
print(self.board.sheet[0])
number_one = int(input("Please enter a number."))
self.board.a = number_one
number_two = int(input("Please enter another number."))
self.board.b = number_two
number_three = int(input("Please enter a third number."))
self.board.c = number_three
number_four = int(input("Please enter a final number."))
self.board.d = number_four
print("Thank you! List updated.")
print(self.board.sheet[0])
class ScoreBoard(object):
def __init__(self):
self.a = "_____"
self.b = "_____"
self.c = "_____"
self.d = "_____"
self.sheet = [f"""
1. Number One: {self.a}
2. Number Two: {self.b}
3. Number Three: {self.c}
4. Number Four: {self.d}
"""]
new_board = ScoreBoard()
new_game = Engine(new_board)
new_game.play_game()
When I print self.board.sheet[0] I would like to show the numbers instead of the lines for self.a through self.d.

You need to recompute self.sheet after self.a through self.d are set. After self.sheet is assigned it just contains a simple string. That string isn't automatically updated when the fields are changed; you have to do it yourself.
Better yet, make sheet a method rather than a static variable.
class ScoreBoard(object):
def __init__(self):
self.a = "_____"
self.b = "_____"
self.c = "_____"
self.d = "_____"
def sheet(self):
return f"""
1. Number One: {self.a}
2. Number Two: {self.b}
3. Number Three: {self.c}
4. Number Four: {self.d}
"""

Related

How to access variables of a sub-function in a class?

I am facing problems with calling a variable outside of a subfunction:
class ABC():
def ___init___(self):
function_A()
function_B()
def function_A(self):
self.A = 5
def subfunction_of_A(self):
self.B = 2
self.function_B()
subfunction_of_A()
def function_B(self):
C = self.B
Start = ABC()
I always geht the error:
'ABC' object has no attribute 'B' for C = self.B
How can I make self.B accessible from outside?
Thanks a lot :)
------- EDIT/UPDATE ----------
Okay, I think i might need to update my question a little bit:
class ABC():
def ___init___(self):
self.function_A()
self.function_B()
def function_A(self):
self.A = 5
def subfunction_of_A(self):
self.B = 2
subfunction_of_A(self)
print(self.B) # This prints 2 and works as it should!
def function_B(self):
C = self.B # In this line I receive the error that ABC.B does not exist --> Why is that?
Start = ABC()
edit:
class ABC():
def __init__(self):
self.function_A()
self.function_B()
def function_A(self):
self.A = 5
def subfunction_of_A(self):
self.B = 2
subfunction_of_A(self)
def function_B(self):
print(self.B) # This prints 2 and works as it should!
C = self.B
Start = ABC()
this time your problem seems to be that your ___init___ has 3 underscores instead of 2... __init__
previous answer:
you're never calling your "sub function"
class ABC():
def function_A(self):
self.A = 5
def subfunction_of_A(self):
self.B = 2
subfunction_of_A(self) # notice this line
def function_B(self):
self.C = self.B
abc = ABC()
abc.function_A()
abc.function_B()
print(abc.C) # prints 2
the only way for B to be set is for that function to run even if its nested...its a weird way to set up a class but there you go

Is it possible to make a variable a reference to a class attribute in Python3?

I want to use a class method that determine which attribute to modify based on the method argument. Here's a very simple analogous version:
class Data:
def __init__(self):
self.a = 1
self.b = 1
def increment(self, a_or_b):
variable = {'a': self.a, 'b': self.b}[a_or_b]
variable += 1
d1 = Data()
d1.increment(a_or_b='a')
print(d1.a)
I want d1.a to equal 2, but it equals 1 because the class attribute hasn't actually been modified, just the variable variable. I could instead define increment as:
def increment(self, a_or_b):
if a_or_b is 'a':
self.a += 1
else:
self.b += 1
But this feels cumbersome, especially if I want the entire alphabet and not just the first two letters. Is there a way to instead make variable a reference to either self.a or self.b such that the attribute gets modified?
You probably shouldn't do this but here's an option.
class Data:
def __init__(self):
self.a = 1
self.b = 1
def increment(self, a_or_b):
if hasattr(self, a_or_b):
setattr(self, a_or_b, getattr(self, a_or_b) + 1)
d1 = Data()
d1.increment('a')
print(d1.a)
This is manipulating the hasattr, setattr, and getattr builtins.
hasattr takes 2 arguments. The object, which is passed in with self, and the attribute name as a string.
getattr takes the same 2 arguments.
setattr takes one additional argument. The value you wish to set to it.
If you have an entire alphabet, then 26 (give or take) individual attributes is the wrong approach. Use a dict.
class Data:
def __init__(self):
self.data = dict.fromkey("abcdefghijklmnopqrstuvwxyz", 1)
def incrementself, c):
self.data[c] += 1

Altering attributes in another class in Python

I have been trying to alter a list in class Inventory from class Pod, but I get an error that I am popping from an empty set. Is there anyway that I can pop from a list from an Inventory instance that I know is populated? Essentially, I am trying to transfer widgets from Inventory to Pod.
class Widget():
def __init__(self):
self.cost = 6
self.value = 9
class Inventory():
def __init__(self):
self.widgets_inv = []
self.cost_inv = 0
self.value_inv = 0
def buy_inv(self):
x = int(input("How many widgets to you want to add to inventory? "))
for i in range(0, x):
self.widgets_inv.append(Widget())
def get_inv(self):
print("You have " + str(len(self.widgets_inv)) + " widgets in inventory.")
def cost_of_inv(self):
cost_inv = len(self.widgets_inv) * Widget().cost
print("The current cost of your inventory is: " + cost_inv + " USD.")
def value_of_inv(self):
val_inv = len(self.widgets_inv) * Widget().value
print("The current value of your inventory is: " + val_inv + " USD.")
class Pod():
"""A pod is a grouping of several widgets. Widgets are sold in pods"""
def __init__(self):
self.pod = []
def creat_pod(self):
x = int(input("How many widgets would you like to place in this pod? "))
for i in range(0, x):
self.pod.append(Widget())
Inventory().widgets_inv.pop()
You should modify the creat_pod-method, so that you can handover the Inventory-object. This allows you to add widgets to the inventory-object before calling creat_pod-method:
def creat_pod(self, inventory):
x = int(input("How many widgets would you like to place in this pod? "))
for i in range(0, x):
self.pod.append(Widget())
inventory.widgets_inv.pop()
In your original code you create always a new Inventory-object, which has therefore and empty widget-list:
Inventory().widgets_inv.pop()

Binary CSP instance

Please am very new in python, and I am trying to do a Binary CSP instance, where it generates variables based on the number of variables the user wants. So if the user wants 4 variables, it generates X1, X2, X3, X4 and then appends to a list. I have tried working on it, still can't place it
class CSP:
def __init__(self, variables):
self.variables = list(variables)
def get_variables(self):
return self.variables
class Map(CSP):
n = input("Enter number of variables: ")
for i in range(n):
vare = 'X' + 'i'
def __init__(self):
super().__init__(self._collect_variables())
def _collect_variables(self):
variables = []
variables.append(self.vare) #list the user appends to
def main():
Map()
if __name__ == '__main__':
main()
Your code is not working for a simple reason: it does not generate several variables. Instead of it, it updates single variable 'vare'.
I should do it in the following way:
class Map(CSP):
self._vare = []
def __init__(self):
n = input("Enter number of variables: ")
for i in range(n):
vare.append ('X' + 'i')
super().__init__(self._get_variables())
def _get_variables(self):
return self._vare

Sorting a dictionary that contains a class holding 5 variable by one of the class variables

I have a dictionary that contains keys that are made from a class containing 5 variables. I want to sort this dictionary by one of the class vars.
here is what i currently have
class Player:
def __init__(self,name,wins,losses,ties,winpercent):
self.__name = name
self.__wins = wins
self.__losses = losses
self.__ties = ties
self.__winpercent = winpercent
# mutators
def setname(self,name):
self.__name = name
def setwins(self,wins):
self.__wins = wins
def setlosses(self,losses):
self.__losses = losses
def setties(self,ties):
self.__ties = ties
def setwinpercent(self,winpercent):
self.__winpercent = winpercent
# accessors
def getname(self):
return self.__name
def getwins(self):
return self.__wins
def getlosses(self):
return self.__losses
def getties(self):
return self.__ties
def getwinpercent(self):
return self.__winpercent
def displayHighScores(self):
print("\n"," "*2,self.__name," "*(24-len(self.__name)),self.__wins)
def displayplayers(self):
print(self.__name)
I store Players like this:
def addplayer(players):
newName = input("\nEnter new Player name or 9 to quit: ")
wins = "0"
losses = "0"
ties = "0"
winpercent = "0"
if not newName:
print("\nNo name detected try again")
addplayer(players)
elif newName == '9':
print("\nReturning to Options menu")
else:
players[newName] = Player(newName,wins,losses,ties,winpercent)
saveData(players)
return players
Finally i am working on a sorted hi scores list. right now i can print my dictionary unsorted like this:
def printhiscores(players):
print("\n"," "*13,"HiScores")
print(" "*3,"Name"," "*20,"Wins")
if len(players) == 0:
print("\nNo current Players in memory.")
else:
for x in players.keys():
players[x].displayHighScores()
DisplayHighScores () being a part of the class object.
I have been reading on dictionary sorting using
OrderedDict(sorted(players.items(), key=itemgetter(1)))
but this returns edit:TypeError: '<' not supported between instances of 'Player' and 'Player'
Again I am looking to sort my dictionary of players by their win attribute and then print this new order to a high score screen. Any help would be greatly appreciated. I will post if i make any more progress on my own on this.
Your Player instances are not orderable however, as they don't implement comparison methods:
TypeError: '<' not supported between instances of 'Player' and 'Player'
If you wanted to sort them by the value returned, say, wins, then just access that information instead of just returning the value:
OrderedDict(sorted(players.items(), key=lambda kv: kv[1].getwins()))
Otherwise, give your Player class rich comparison methods; methods by which to determine when one instance should be sorted before or after another. You'll also need an equality test. It's easier to just implement support for < (lower then) and equality, then use the #functools.total_ordering decorator to provide the rest:
from functools import total_ordering
#total_ordering
class Player:
def __lt__(self, other):
if not isinstance(other, Player):
return NotImplemented
return self.__wins < other.__wins
def __eq__(self, other):
if not isinstance(other, Player):
return NotImplemented
return self.__wins == other.__wins
The above makes two Player instances equal when their wins are equal, and orders them by that attribute. You'll need to adjust this for your application as needed.

Resources