How to use dictonary to create an object? - python

I'm new in stackoverflow and I'd like to make my first question for a problem in this code I've tried to write to learn objects in python.
I'm trying to call the creation of an object through a dictionary.
My purpose is to create an object thanks to a number, for example I have the dictionary newch = {1 : Character.new_dragon(), 2 : Character.new_goblin()} and when I call Player1 = newch[1] it should create a new dragon (#classmethod new_dragon) and assign it to Player1
The problem is that when i run the program, Character.new_dragon() and Character.new_goblin() are called automatically (i put a control print), but when I write "DRAGO" after the request "which player?" the functions aren't called because there isn't the control print
import random
class Character:
def __init__(self,idd,height,weight,att,defe):
self.idd=idd
self.height=height
self.weight=weight
self.att=att
self.defe=defe
#classmethod
def new_goblin(cls):
print('newgoblin')
return cls(1,getr(1,1.5,0.1),getr(40,60,0.5),getr(5,15,1),getr(6,10,1))
#classmethod
def new_dragon(cls):
print('newdrago')
return cls(2,getr(20,30,1),getr(500,2000,5),getr(50,150,3),getr(20,100,3))
def getr(start,stop,step): #returns float
x=random.randint(1, 1000)
random.seed(x)
return random.randint(0, int((stop - start) / step)) * step + start
play={1:'p1', 2:'p2', 3:'p3', 4:'p4'} #dict for players
newch={1:Character.new_dragon(),2:Character.new_goblin()} ############This doesn't work
i=1
while True:
char=input("which player? Drago or Goblin?").upper()
if(char=="DRAGO"):
play[i]=newch[1] #here i try to call Character.new_dragon()
i+=1
break
elif(char=="GOBLIN"):
play[i]=newch[2]
i+=1
break
print("write \'Drago\' or \'Goblin\'")
print(play[1].height, play[1].weight, play[1].att, play[1].defe)
Here's my code, if you could help me, I would be very glad, thanks

The new object is created immediately when you call Character.new_dragon(), and the object is then stored in the dict.
Instead you could not store the object in the dict, but the function that creates it. That function would be Character.new_dragon (without the ()). Then you can call that function when the player selects a character:
play[i]=newch[1]()
Complete code:
import random
class Character:
def __init__(self,idd,height,weight,att,defe):
self.idd=idd
self.height=height
self.weight=weight
self.att=att
self.defe=defe
#classmethod
def new_goblin(cls):
print('newgoblin')
return cls(1,getr(1,1.5,0.1),getr(40,60,0.5),getr(5,15,1),getr(6,10,1))
#classmethod
def new_dragon(cls):
print('newdrago')
return cls(2,getr(20,30,1),getr(500,2000,5),getr(50,150,3),getr(20,100,3))
def getr(start,stop,step): #returns float
x=random.randint(1, 1000)
random.seed(x)
return random.randint(0, int((stop - start) / step)) * step + start
play={1:'p1', 2:'p2', 3:'p3', 4:'p4'} #dict for players
newch={1:Character.new_dragon,2:Character.new_goblin} ############This doesn't work
i=1
while True:
char=input("which player? Drago or Goblin?").upper()
if(char=="DRAGO"):
play[i]=newch[1]() #here i try to call Character.new_dragon()
i+=1
break
elif(char=="GOBLIN"):
play[i]=newch[2]()
i+=1
break
print("write \'Drago\' or \'Goblin\'")
print(play[1].height, play[1].weight, play[1].att, play[1].defe)
This works, however I would not say it is the best coding style. Its hard to judge from only this piece of code, but it might be a better idea to make Drago and Goblin subclasses of the Character class and store the type of those classes in that dictionary.

newch={1:Character.new_dragon(),2:Character.new_goblin()}
As this is written, the new_dragon and new_goblin functions are called when the dictionary is created. This is why you are seeing them both run "automatically" every time you run your program.
If you instead declared the dict like:
newch={1:Character.new_dragon ,2:Character.new_goblin}
And later have something like:
if(char=="DRAGO"):
play[i]=newch[1]()
(note the parenthesis after the newch[1]) you should get what you want.
Incidentally, those break statements aren't necessary. The If/elif/else chain doesn't fall through like a switch statement in other languages.

When you are initialising the dictionary this way:
newch={1:Character.new_dragon(),2:Character.new_goblin()}
You are binding keys (1 and 2) to the return values of the new_dragon and new_goblin functions. You need to bind the functions(without calling them) like so:
newch={1:Character.new_dragon,2:Character.new_goblin}
Notice there are no brackets!
And then, when you create players, you execute those functions like so:
play[i]=newch[1]() Notice here we have brackets!
Additionally, if I may suggest an improvement of the code here:
if(char=="DRAGO"):
play[i]=newch[1]()
i+=1
To avoid the if statement, you can create you mapping with a string:
newch={"DRAGO":Character.new_dragon,"GOBLIN":Character.new_goblin}
And create instances just by calling
play[i]=newch[char]()
To handle errors, you can add just a single if statement checking whether the char string is in the list with dict keys.

Related

Python - why isnt my function outputting 'a' ten times? Beginner question

def testfunction():
for i in range(10):
return('a')
print(testfunction())
I want 'a' outputed 10 times in one line. If I use print instead of return, it gives me 10 'a's but each on a new line. Can you help?
return terminates the current function, while print is a call to another function(atleast in python 3)
Any code after a return statement will not be run.
Python's way of printing 10 a's would be:
print('a' * 10)
In your case it would look like the following:
def testfunction ():
return 'a' * 10
print(testfunction ())
The reason its only printing once is because the return statment finishes the function (the return function stops the loop).
In order to print 'a' 10 times you want to do the following:
def testfunction():
for i in range(10):
print('a')
testfunction()
If you want "a" printed 10 times in one single line then you can simply go for:
def TestCode():
print("a"*10)
There's no need to use the for loop. For loop will just "a" for 10 times but every time it'll be a new line.
You can also take in a function argument and get "a" printed as many times as desired.
Such as:
def TestCode(times):
t = "a"*times
print(t)
Test:
TestCode(5)
>>> aaaaa
TestCode(7)
>>> aaaaaaa
print and return get mixed up when starting Python.
A function can return anything but it doesn't mean that the value will be printed for you to see. A function can even return another function (it's called functional programming).
The function below is adapted from your question and it returns a string object. When you call the function, it returns the string object into the variable called x. That contains all of the info you wanted and you can print that to the console.
You could have also used yield or print in your for loop but that may be outside of the scope.
def test_function(item:str="a", n:int=10):
line = item*n # this will be a string object
return line
ten_a_letters = test_function()
print(ten_a_letters)
"aaaaaaaaaa"
two_b_letters = test_function("b",2)
print(two_b_letters)
"bb"
I want 'a' outputed 10 times in one line. If I use print instead of
return, it gives me 10 'a's but each on a new line.
If you want to use print, the you need to pass a 2nd parameter as follows:
def testfunction():
for i in range(10):
print('a', end='')
However, I think the pythonic way would be to do the following:
def testfunction():
print('a' * 10)
When you use return you end the execution of the function immediately and only one value is returned.
Other answers here provide an easier way to solve your problem (which is great), but I would like to suggest a different approach using yield (instead of return) and create a generator (which might be an overkill but a valid alternative nonetheless):
def testfunction():
for i in range(10):
yield('a')
print(''.join(x for x in testfunction()))
1. What does "yield" keyword do?
def test ():
print('a' * 10)
test()
Output will be 'aaaaaaaaaa'.

How to complete this function then print it out, using Python?

I'm having a hard time to understand how to work with functions - I can make then but after that I don't know how to use them. My question is how can I print this code with a function?
string = "Hello"
reverse = string[::-1]
print(reverse)
I tried putting it in a function but I cannot make it print Hello.
def reverse_a_string(string):
string = "Hello"
reverse = string[::-1]
print(reverse)
also tried this
def reverse_a_string(string):
string = "Hello"
reverse = string[::-1]
print(reverse)
Nothing seems to work. I'm having same problem with this as well.
total = 0
def length(words):
for i in words:
total += 1
return total
Functions without a return value
Functions that just take action or do something without returning a value (for example, print).
Functions that don't return a value can be defined like that:
def sayHello():
print "Hello!"
And can be used (called) like that:
sayHello()
And the output will be:
Hello!
Function parameters
A function can also receive parameters (type of variables) from the caller. It's better to demonstrate it with an example.
A function that receives a name and greets this name:
def sayHelloTo(name):
print "Hello", name
It can be called like that:
sayHelloTo("Yotam")
And the output will be:
Hello Yotam
The parameters are the function's input.
Functions with a return value
Other functions, unlike sayHello() or sayHelloTo(name) (that just do something) can return a value. For example, let's make a function that rolls a dice (returns a random number between 1 and 6).
from random import randint
def rollDice():
result = randint(1, 6)
return result
The return keyword just sets the output value of the function and exits the function. An example use of the rollDice function will be:
dice = rollDice()
print "The dice says", dice
When the function hits a return keyword, it finishes and the return value (in our case, the variable result) will be placed instead of the function call. Let's assume randint(1, 6) has produced the number 3.
Result becomes 3.
Result is returned.
Now, instead of the line:
dice = rollDice()
We can treat the line as:
dice = 3
(rollDice() was replaced with 3)
Functions with parameters and a return value
Some functions (for example, math functions) can take inputs AND produce outputs. For example, let's make a function that receives 2 numbers and outputs the greater one.
def max(a,b):
if a > b:
return a
else:
return b
What it does is pretty clear, isn't it? If a is greater, it returns the value of it. Otherwise, returns the value of b.
It can be used like that:
print max(4, 6)
And the output will be:
6
Now, your case
What you want to do is a function that reverses a string. It should take 1 parameter (input) - the string you want to reverse, and output 1 value - the reversed string. This can be accomplished like that:
def reverse_a_string(my_text):
return my_text[::-1]
now you can do something like that:
s = raw_input("Please enter a string to be reversed\n") #input in Python3
r = reverse_a_string(s)
print r
r will contain the reversed value of s, and will be printed.
About your second function - well, I assume that based on this answer you can make it yourself, but comment me if you need assistance with the second one.
Local variables
About your 3rd example:
def reverse_a_string(string):
string = "Hello"
reverse = string[::-1]
print(reverse)
This is something that is really worth delaying and understanding.
the variable reverse is first used inside the function. This makes it a local variable.
This means that the variable is stored in the memory when the function is called, and when it finishes, it is removed. You can say it's lifetime is from when the function is called to when the function is done.
This means that even if you called reverse_a_string(string), you wouln't be able to use the reverse variable outside of the function, because it would be local.
If you do want to pass a value like that, you have to "declare" your variable outside of the function and to use the global keyword, like that:
reverse = "" #This makes reverse a global variable
def reverse_a_string(string):
global reverse #Stating that we are going to use the global variable reverse
reverse = string[::-1]
# Then you can call it like that:
reverse_a_string("Hello")
print reverse
The output will be
olleH
Although it's strongly not recommended to do it in Python, or in any other language.
Once you create a function you must call it. You have created the function reverse_a_string but then you never actually call it. Think about a function as a button that does something everytime it is pushed (or in our case called). If you never push the button then although it has the potential to do something, it never will. In order for the set of instructions to happen we need to push the button (or in our case call the function). So in order for your code to work you first need to define the function then actually call it:
def reverse_a_string():
string="Hello"
reverse = string[::-1]
print reverse
reverse_a_string()
Result: 'olleH'
If you want to pass your own string in to the function so it doesn't just return 'olleH' all the time your code needs to look like such:
def reverse_a_string(stringThatWillBeReversed):
reverse = stringThatWillBeReversed[::-1]
print reverse
reverse_a_string('whateverStringYouWant')
Result: The reverse of the string you entered.
Hope that helps!
I don't know whether you are asking how to define functions in python or something else
If you want to learn python functions, go to http://www.tutorialspoint.com/python/python_functions.htm or just write python tutorial in google, you will get billions of good sites
def reverse_a_string(string):
#function definition
reverse = string[::-1]
print(reverse)
#function call
reverse_a_string("your string")
But you to define function for this, you could simply do
print( string[::-1] )
# defines the 'Reverse a String' function and its arguments
def reverse_a_string():
print(string)
reverse = string[::-1]
print(reverse)
print("Type a string") # asks the user for a string input
string = input() # assigns whatever the user input to the string variable
reverse_a_string() # simply calls the function
for functions, you have to define the function, then simply call it with the function name i.e. funtion()
In my example, I ask for a string, assign that to the variable, and use it within the function. If you just want to print hello (I'm a little unclear from your question) then simply including the print("hello") or w/ variable print(string) will work inside the function as well.

Using the same variables in different functions in Python

I'm trying to use the return function, I'm new to python but it is one of the things I don't seem to understand.
In my assignment I have to put each task in a function to make it easier to read and understand but for example I create a randomly generated number in a function, I then need the same generated number in a different function and I believe the only way this can be done is by returning data.
For example here I have a function generating a random number:
def generate():
import random
key = random.randint(22, 35)
print(key)
But if I need to use the variable 'key' again which holds the same random number in a different function, it won't work as it is not defined in the new function.
def generate():
import random
key = random.randint(22, 35)
print(key)
def number():
sum = key + 33
So how would I return data (if that is what you need to use) for it to work?
The usage of return indicates to your method to 'return' something back to whatever called it. So, what you want to do for example in your method is simply add a return(key):
# Keep your imports at the top of your script. Don't put them inside methods.
import random
def generate():
key = random.randint(22, 35)
print(key)
# return here
return key
When you call generate, do this:
result_of_generate = generate()
If you are looking to use it in your number method, you can actually simply do this:
def number():
key = generate()
sum = key + 33
And if you have to return the sum then, again, make use of that return in the method in similar nature to the generate method.

Is my prof wrong?

I'm solving a problem and something confuses me. In following code isn't
counts = mapReduce(lines, mapper=computeWordCounts, reducer=sumUpWordCounts);
just wrong? Is that just a pseudocode or such usage is actually possible?
def computeWordCounts(line):
# TODO
def sumUpWordCounts(word, counts):
# TODO
def mapReduce(data, mapper, reducer):
# TODO
def test():
with open('/Users/bgedik/Desktop/zzz.txt') as f:
lines = f.read().splitlines()
counts = mapReduce(lines, mapper=computeWordCounts, reducer=sumUpWordCounts);
for word, count in counts:
print word, " => ", count
in python functions and classes are first class citizens you can pass them around just like any other variable
def square(a_var):
return a_var ** 2
def apply(value,fn):
return fn(value)
print apply(5,square)
you can also rename them
sq = square
print sq(5)
there is alot more than this see the docs https://docs.python.org/2/library/stdtypes.html#functions
It's perfectly valid, they're called named arguments. They're a way of skipping arbitrary arguments in the middle of the function all, and still knowing which ones you're actually sending.
This pattern is actually very widespread, from VB6 to C# and more!

dynamic class instantiation confusion in python

I asked a similar, yet lousy, question very late last night (Access to instance variable, but not instance method in Python) that caused a fair bit of confusion. I'd delete it if I could, but I can't.
I now can ask my question more clearly.
Background: I'm trying to build a black-jack game to learn python syntax. Each hand is an instance of the Hand class and I'm now at the point where I'm trying to allow for hands to be split. So, when it comes time for a hand to be split, I need to create two new hand instances. Given that further splits are possible, and I want to reuse the same methods for re-splitting hands. I therefore (I think) need to dynamically instantiate the Hand class.
Following is a code snippet I'm using to block out the mechanics:
import os
os.system("clear")
class Hand():
instances=[]
def __init__(self, hand_a, name):
Hand.instances.append(self)
self.name = name
self.hand_a = hand_a
def show_hand(self):
ln = len(self.hand_a)
for x in range(ln):
print self.hand_a[x]
class Creation():
def __init__(self):
pass
def create_name(self):
hil = len(Hand.instances)
new_name = 'hand_' + str(hil + 1)
return(new_name)
def new_instance(self):
new_dict = {0: 'Ace of Clubs', 1: '10 of Diamonds'}
new_hand_name = {}
new_hand_name.setdefault(self.create_name(), None)
print new_hand_name
new_hand_name[0] = Hand(new_dict, self.create_name())
print new_hand_name[0]
hand = Hand("blah", 'hand')
hand_z = Hand("blah_z", 'hand_z')
creation = Creation()
creation.new_instance()
here is the output:
{'hand_3': None}
<__main__.Hand instance at 0x10e0f06c8>
With regard to the instance created by the following statement:
new_hand_name[0] = Hand(new_dict, self.create_name)
Is new_hand_name[0] new the variable that refers to the instance?
Or, is hand_3 the variable?
i.e. when calling an instance method, can I use hand_3.show_hand()?
First, to answer your questions: new_hand_name[0] is the variable that refers to the instance- more specifically, it is the value in the new_hand_name dictionary accessed by the key 0. The new_hand_name dictionary, if you printed it, would look like:
{'hand_3': None, 0: <__main__.Hand instance at 0x10e0f06c8>}
Adding the value of "hand_3" to the dictionary is unnecessary, but for that matter, so is the dictionary.
What you really want to do has nothing to do with dynamic instantiation of new classes, which has nothing to do with your problem. The problem is that a Hand might represent a single list of cards, but might also represent a list of lists of cards, each of which have to be played separately. One great way to solve this is to make a separation between a player and a hand, and allow a player to have multiple hands. Imagine this design (I'm also leaving out a lot of the blackjack functionality, but leaving a little in to give you an idea of how to work this in with the rest of the program).
def draw_random_card():
"""
whatever function returns a new card. Might be in a Deck object, depends on
your design
"""
# some code here
class Player:
def __init__(self):
self.hands = []
def deal(self):
"""add a random hand"""
self.hands.append(Hand([draw_random_card(), draw_random_card()]))
def split(self, hand):
"""split the given hand"""
self.hands.remove(hand)
self.hands += hand.split()
class Hand:
def __init__(self, cards):
self.cards = cards
def hit(self):
"""add a random card"""
self.cards.append(draw_random_card())
def split(self):
"""split and return a pair of Hand objects"""
return [Hand(self.cards[0], draw_random_card()),
Hand(self.cards[1], draw_random_card())]
Isn't that simpler?
In response to your comment:
You can refer to any specific hand as self.hands[0] or self.hands[1] within the Players class.
If you want to keep track of a particular hand, you can just pass the hand itself around instead of passing a character string referring to that hand. Like this:
def process_hand(hand):
"""do something to a hand of cards"""
h.hit()
print h.cards()
h.hit()
h = Hand(cards)
process_hand(h)
This is important: modifications you make to the hand in the function work on the actual hand itself. Why put the extra step of passing a string that you then have to look up?
Also note that information specific to each hand, such as the bet, should probably be stored in the Hand class itself.
If you are sure you want to refer to each hand with a specific name (and again, it's not necessary in this case), you just use a dictionary with those names as keys:
self.hands = {}
self.hands["hand1"] = Hand([card1, card2])
self.hands["hand2"] = Hand([card1, card2])
print self.hands["hand1"]
But again, there is probably no good reason to do this. (And note that this is very different than instantiating a new variable "dynamically". It would be a good idea to look into how dictionaries work).

Categories