I am a beginner at coding and currently in a python class at my university. I'm having some issues pop up in the "Problems" tab in Visual Studio Code. It wants me to put a self argument in my function inside a class, however when I call the class in my other file the code works it just displays problems. I tried putting self into the classes code and then everything stops working. The code was copied during the lecture and is the same code as my professor's using the same coding platform however his code doesn't show problems. I am attaching 2 screen shoots since the code is from 2 different files. I'm guessing something in my settings is causing this to happen. I have a similar thing happen when I do something like.for i in something: it will tell me i isn't defined yet the code will work.
Screenshot 1
Screenshot 2
Inside a class, that has non static methods, there must be a self variable.
class Math_Functions:
def addition(self, x, y): # there must be a self
return x + y
#... so on
This seems to be a static method, but VC may require you to still provide a self reference. Because python (at this specific case) does not require the self reference by default, when imported your code works file, but standalone, VC may tell you that you need an extra self there. Also you have an extra comma in addition after your y parameter.
Just simply pass in self into each of the methods (math functions), although it may work without it, it's good practice to do this if you want to continue learning OOP.
class mathFunctions:
def add(self, x, y): #Avoids the problem in VS
return x + y
It is required to pass in self for it to work when creating an object using a class using init, for example:
class employee:
def __init__(self, firstName, lastName, age):
self.firstName = firstName
self.lastName = lastName
self.age = age
def fullName(self):
return self.firstName + ' ' + self.lastName
#creating an object within the class
John = employee('John', 'Smith', '26')
#Returns "John Smith"
print(John.fullName())
Hope this might help, good luck on your python class!
This is a response to both replies. Putting self into the code creates a different problem and the code won't run because it tells me I am "missing 1 required positional argument: 'y'"
Three solutions:
First One:
In settings.json file add this configuration:
"python.linting.pylintArgs": [
"--disable=all",
"--enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode",
"--disable=no-self-argument"
],
The first and second settings are the default settings of pylint, the third one can suppress the warning.
Second One:
Change your code to these:
main:
from calc import Math_functions as mf
print("Welcom to Calculator!")
x = int(input('Number: '))
y = int(input('Number: '))
op = input('Operation: ')
f = mf(x, y)
if op == '+':
print(f.addition())
elif op == '-':
print(f.subtraction())
elif op == '*':
print(f.multiplication())
elif op == '/':
print(f.division())
calc:
class Math_functions:
def __init__(self, x, y):
self.x = x
self.y = y
def addition(self):
return self.x+self.y
def subtraction(self):
return self.x-self.y
def multiplication(self):
return self.x*self.y
def division(self):
return self.x/self.y
Third One:
Change your code to these:
main:
import calc as mf
print("Welcom to Calculator!")
x = int(input('Number: '))
y = int(input('Number: '))
op = input('Operation: ')
if op == '+':
print(mf.addition(x, y))
elif op == '-':
print(mf.subtraction(x, y))
elif op == '*':
print(mf.multiplication(x, y))
elif op == '/':
print(mf.division(x, y))
calc:
def addition(x, y):
return x+y
def subtraction(x, y):
return x-y
def multiplication(x, y):
return x*y
def division(x, y):
return x/y
Related
I know that I have a misunderstanding of how Python attributes work because I'm here writing this problem, but I don't know exactly what I'm misunderstanding. I'm trying to get
self.card = self.hand[self.card_number].split()
self.card_val = deck.ranks.get(self.card[0])
to attain their values based on self.hand, which I pass to __init__ upon instantiation. Throughout the game I am altering .hand, and I want .card & .card_val to change every time I change .hand, instead of having to tell it to do that elsewhere (outside of the attribute definitions). I know there is a way to do this, or at least I think there is, and by that I mean simply by defining their values as inherited based on whatever .hand is at any given time, without calling an internal or external function.
In the posted code, I have altered it to work as the game instructions require, using...
def get_card_vals(p1, p2):
for player in [p1, p2]:
player.card = player.hand[player.card_number].split()
player.card_val = deck.ranks.get(player.card[0])
print("{a} vs. {b}".format(a = p1.card, b = p2.card))
print("---------------------------")
...but that's what I want to change. I want what that function is doing to be executed more concisely inside of the attribute definitions upon handling of the instance. Basically my question is why can't these two attributes get their values directly from the first attribute that I define via "hand" passed to the init?
Any help would be appreciated, and more importantly, I think more than just solutions, it would help me even more to understand what I am misunderstanding about how attributes, instances, and instantiation and all that works so that I know where my thinking is wrong. Thanks!
import random
from random import shuffle
from collections import deque
class Deck():
def __init__(self):
self.ranks = {"Ace":14, "King":13, "Queen":12, "Jack":11, "10":10, "9":9, "8":8, "7":7, "6":6, "5":5, "4":4, "3":3, "2":2}
self.suites = ["Heart", "Diamond", "Spade", "Club"]
self.cards = []
def create_cards(self):
for suite in self.suites:
for key in self.ranks.keys():
self.cards.append(key + " " + suite)
def shuffle(self):
random.shuffle(deck.cards)
deck = Deck()
deck.create_cards()
deck.shuffle()
class Player():
def __init__(self, hand):
self.name = "name"
self.hand = hand
self.card_number = 1
self.card = self.hand[self.card_number].split()
self.card_val = deck.ranks.get(self.card[0])
def war(bool, p1, p2):
if bool == True:
for player in [p1, p2]:
player.card_number = 4
else:
for player in [p1, p2]:
player.card_number = 0
p2 = Player(deque(deck.cards[::2]))
p1 = Player(deque(deck.cards[1::2]))
p2.name = "The Computer"
def get_card_vals(p1, p2):
for player in [p1, p2]:
player.card = player.hand[player.card_number].split()
player.card_val = deck.ranks.get(player.card[0])
print("{a} vs. {b}".format(a = p1.card, b = p2.card))
print("---------------------------")
def cant_war_lose(winner, loser):
print("{a} doesn't have enough cards to go to war, so {b} wins the Battle!".format(a = loser, b = winner))
def battle_win(winner, loser):
print("{a} has run out of cards, therefore {b} has won via Battle!".format(a = loser, b = winner))
def play_cards(p1, p2):
war(False, p1, p2)
get_card_vals(p1, p2)
if p1.card_val > p2.card_val:
p1.hand.append(p2.hand.popleft())
p1.hand.rotate(-1)
elif p1.card_val == p2.card_val:
if len(p1.hand) < 5 or len(p2.hand) < 5:
if len(p1.hand) > len(p2.hand):
cant_war_lose(p1.name, p2.name)
else:
cant_war_lose(p2.name, p1.name)
return 0
else:
input("War is inititated! Press Enter to continue!")
print("---------------------------")
war(True, p1, p2)
get_card_vals(p1, p2)
if p1.card_val > p2.card_val:
for i in range(0,5):
p1.hand.append(p2.hand.popleft())
p1.hand.rotate(-5)
elif p1.card_val < p2.card_val:
for i in range(0,5):
p2.hand.append(p1.hand.popleft())
p2.hand.rotate(-5)
else:
p1.hand.rotate(-1)
p2.hand.rotate(-1)
elif p1.card_val < p2.card_val:
p2.hand.append(p1.hand.popleft())
p2.hand.rotate(-1)
if len(p1.hand) != 0 and len(p2.hand) != 0:
input("After the last round of Battle, {a} now has {b} cards, and {c} now has {d} cards! Press Enter to continue!".format(a = p1.name, b = len(p1.hand), c = p2.name, d = len(p2.hand)))
print("---------------------------")
else:
if len(p1.hand) > len(p2.hand):
battle_win(p1.name, p2.name)
else:
battle_win(p2.name, p1.name)
return 0
def game_run():
run = 1
p1.name = input("Player 1's name? ")
print("---------------------------")
while run == 1:
if play_cards(p1, p2) == 0:
run = 0
game_run()
You can use the property decorator to create a calculated property
class Player():
def __init__(self, hand):
self.name = "name"
self.hand = hand
self.card_number = 1
#property
def hand(self):
return self._hand
#hand.setter
def hand(self, value):
self._hand = value
self.card = self._hand[self.card_number].split()
self.card_val = deck.ranks.get(self.card[0])
What you misunderstand is variables, not instances. For instance, the attribute card is a scalar variable attached to the instance. Assigning to it with
self.card = <blah>
does not bind it to blah for constant recomputation. This is a value assignment, not a memory mapping. If you want that long-term binding, you must either write the maintenance routine yourself -- which you've already done, in a way, with the consistent recomputation -- or you must assign a mutable reference to self.card, so that card refers to teh same object as the expression you created.
Given that you are consistently rotating and altering the hand, this is not feasible in your design. Instead, simply write an access routine, perhaps get_next_card(hand), which will rotate the hand, extract the card, and return the desired rank and suit.
If you plan to program more card games, you will also find it handy to define a class card and class hand, with appropriate support routines. Maintain the card as a pair of integers; convert to strings only for printing.
Does that get you moving?
For anyone who wanted to compare a before and after of the problem & final solution, below is the working code for my specific issue. All I had to do was convert self.card and self.card_val to a calculated property. By passing in hand, and subsequently handling only hand, self.card & self.card_val are calculated, since every time I handle the instance of the class (by handling hand), these "method attributes" are being called and altered. Thanks for the input, guys!
class Player():
def __init__(self, hand):
self.name = "name"
self.card_number = 1
self.hand = hand
#property
def card(self):
return self.hand[self.card_number].split()
#property
def card_val(self):
return deck.ranks.get(self.card[0])
Our teacher has assigned us an assignment for doing a turned based game.
This only included name.strip() but this does not prompt player to input unique name:
def start():
print("\nNew game started...Setting up Player 1's team...\n")
for total_characters in range (1,4):
name = input('Enter a unique name for unit #'+str(total_characters)+'==> ')
if not name.strip():
print('Cant be blank name,please provide a unique name')
return start()
else:
role_selection()
def role_selection():
for total_characters in range (1):
role = input('Select unit #'+str(total_characters)+' type: (W)arrior, (T)anker, or Wi(Z)ard ==> ')
total_characters+=1
if role.upper() == 'W':
pass
elif role.upper() == 'T':
pass
elif role.upper() == 'Z':
pass
else:
print("I don't understand what are you typing.")
return role_selection()
There are things that doesn't make sense :
You have the exact same function twice :
def set_up(team_size)
def set_up(name)
You are doing :
for total_units in range(team_size):
[...]
invalid = True
[...]
while invalid: # Infinite loop
set_up() # What's this function ?
As you can see from the comments in the code above, you never set invalid to False, leading to the infinite loop.
Note: My recommendation is that you should check out some tutorial on python before moving on coding a complex project, because your homework is not that easy.
Edit :
From the new code you've posted, you could do something like this :
def new_game():
names = []
for unit_id in range(1,4):
print(f'Enter a unique name for unit #{unit_id} ->')
empty = True
while empty:
name = input('>')
if name == "":
continue
empty = False
if name in names:
print('Unit name must be unique.')
else:
print('Name looks good!')
names.append(name)
python menu
At first glance, this stood out to me:
if not name.strip():
print('Unit name could not be blank.')
invalid = True
Remember in python the indentation matters. You are setting invalid to True regardless of the if condition. Further down you have a while loop that checks it.
The other if conditions have invalid=True inside the condition. Plus you don't have invalid=False anywhere as far as I see, so you'll get an error if you don't declare it somewhere so it's always on the path before the while.
this doesn't seem like a specific problem, more an ask for general guidance for going about this kind of problem?
One thing to note is that your above script only uses functions (which store behaviour) whilst really for something like the turn based game, you need to store behaviour (attacks etc) and information (how much health is left etc).
I won't write the script for you, but here's an example of how you might define an rpg like entity, capable of attacking, being attacked by another entity etc:
class Entity:
"""Abstract class for any combat creature"""
def __init__(self, name, health):
self.name = name
self.health = health
self.is_alive = True
def attack(self, other):
dmg = random.randint(7, 12)
other.be_attacked(dmg)
def be_attacked(self, dmg):
self.health = self.health - dmg
if self.health <= 0:
self.die()
def die(self):
self.is_alive = False
def check_life(self):
return self.is_alive
You can then initialise a bunch of these to make up the 'team' you where talking about:
one_person = Entity('Lee', 34)
another_person = Entity('Someone Else', 21)
etc. Hope that helps a bit. Good luck with your project and have fun!
I'm trying to get my code to output the results of really any code to my terminal, but I can't seem to find out why it won't print. I'm just learning to code so I've been finding a lot of explanation on this site kind of confusing, so apologies if this has been asked before.
This is my python file python.py:
class point(object):
def __init__(self, x, y):
self.x = float(x);
self.y = float(y);
def __str__(self):
return("(" + self.x + "," + self.y + ")")
def main():
first = point(2,3)
if __name__ == '__main__':
main()
and in the terminal I'm just typing "python python.py"
Add a print statement in the main() function to print to terminal:
class point(object):
def __init__(self, x, y):
self.x = float(x);
self.y = float(y);
def __str__(self):
return("(" + self.x + "," + self.y + ")")
def main():
first = point(2,3)
print(first)
if __name__ == '__main__':
main()
As others have mentioned, you need to add a print() call in your main function in order to get output to the terminal. Additionally, a few other things to note: Python doesn't require semi-colons, so there's no need for them in your __init__() method and you can't implicitly convert floats to strings, so you have to be explicit in your __str__() method.
class point(object):
def __init__(self, x, y):
self.x = float(x)
self.y = float(y)
def __str__(self):
# explicitly cast floats to strings
return "(" + str(self.x) + "," + str(self.y) + ")"
def main():
first = point(2,3)
print(first)
if __name__ == '__main__':
main()
Also, as MrTrustworthy pointed out, you don't need to call Class.__str__() directly as print first calls the __str__() method associated with the class. If there's no such method and implicit conversion fails, then you will get the representation of the calling function and the address in memory.
If you remove __str__() from your example, you should get output like this: <__main__.point object at 0x7f184cec4b70> if you try to print the object.
class LogicGate(object):
def __init__(self, n):
self.label = n
self.output = None # ????????????
def getOutput(self):
self.output = self.performGateLogic()
return self.output
def getLabel(self):
return self.label
class BinaryGate(LogicGate):
def __init__(self, n): # ?????????????????
LogicGate.__init__(self, n)
self.pinA = None # ??????????????
self.pinB = None # ??????????????
def getPinA(self):
return int(raw_input('Enter Pin A input for gate' + self.getLabel() + '-->'))
def getPinB(self):
return int(raw_input('Enter Pin A input for gate' + self.getLabel() + '-->'))
class UnaryGate(LogicGate):
def __init__(self, n): # ??????????????
LogicGate.__init__(self, n)
self.pin = None # ?????????????
def getPin(self):
return int(raw_input('Enter Pin input for gate' + self.getLabel() + '-->'))
class AndGate(BinaryGate):
def __init__(self, n): # ????????????
BinaryGate.__init__(self, n)
def performGateLogic(self):
a = self.getPinA()
b = self.getPinB()
if a == 1 and b == 1:
return 1
else:
return 0
This code belongs to Problem Solving with Algorithms and Date Structures.
When I remove the lines before the comment '# ????????', the code can run normally.
Why does the author write the code like this?
Whether is it a good code style?
Can I always remove these lines before the comment '# ????????' ?
The author writes the code like that because it is good practice to never have uninitialised members and class parents, static checkers moan if you do.
The reason that it is not good practice is for future maintainability - let us say that the base class, LogicGate, was to gain a new property - say propagation_delay and a new method that allowed simulations to called get_response_time which relied on the current output state and the required, possibly new, state. If all the code that was derived from that class did the correct initialisations then it would all work fine, without any changes. If you remove those lines and such a new method was introduced you would have to go back through all of the child classes adding them back in before your final class would work for that method, with the chance that you would miss one.
Daft as it sounds doing things properly now is actually future laziness - it only takes you seconds when you are creating a class to make sure everything is initialised - debugging an uninitialised class can take hours.
First:
The __init__ functions are the constructors of the classes, you can read about them here.
Second:
Your code will run without those lines but the question is why and is it ok to remove them?
For example if you remove the following init
class UnaryGate(LogicGate): # LogicGate is the superclass
def __init__(self, n):
LogicGate.__init__(self, n)
The constructor of the super-class LogicGate will be called directly.
Third:
Ok, so can we remove the self.xxx = None?
class BinaryGate(LogicGate):
def __init__(self, n):
LogicGate.__init__(self, n)
self.pinA = None
self.pinB = None
We could remove those 2 Lines too but consider this code
bg = BinaryGate("binaryGate1")
print bg.pinA
This would throw an error because pinA is undefined.
If you do not remove the self.pinA = None in __init__ the code will run and None will be printed.
I am struggling to make this simple code work. I've just started to learn OOP. I looked at other examples but none could point in the right direction. The error is
TypeError: SetStrength() missing 1 required positional argument: 'strength'
import random
class Character:
"""A game character that has strength and skill"""
#constructor
def __init__(self):
#set the attributes with an initial value
self._name = ''
self._strength = 0
self._skill = 0
def SetName(self, name):
self._name = name
def SetStrength(self, strength):
self._strength = calculateAttribute()
def SetSkill(self, skill):
self._skill = calculateAttribute()
def GetName(self):
return self._name
def GetStrength(self):
return self._strength
def GetSkill(self):
return self._skill
def report(self):
return{'name':self._name,'strength': self._strength, 'skill':self._skill}
def calculateAttribute():
return (random.randrange(1,13)//random.randrange(1, 5)) + 10
def main():
player1 = Character()
player1.SetName('James')
player1.SetStrength()
player1.SetSkill()
print(player1.report())
if __name__ == "__main__":
main()
That method is defined as def SetStrength(self, strength):. That means that, in addition to the self which is passed automatically, you need to provide an additional argument - in this case, the new strength value you'd like to set. It works very similarly to setName, which you call with an argument on the previous line.
That said, the code you're working with is Java/C++/etc. code translated into Python, which balloons the size of the code for no good reason.
You should remove the expected argument "strength" of your function "SetStrength". Same for "skill" and "SetSkill".
Try this:
def SetStrength(self):
self._strength = calculateAttribute()
def SetSkill(self):
self._skill = calculateAttribute()