I realize I've been pretty much spamming this forum lately, I'm just trying to break my problems down since I'm supposed to create a yahtzee game for assignment. My code is currently looking like this:
class Player:
def __init__(self,name):
self.name=name
self.lista={"ones":0,"twos":0,"threes":0, "fours":0,"fives":0,"sixs":0,"abovesum":0,"bonus":0,"onepair":0,"twopair":0,"threepair":0,"fourpair":0,"smalladder":0,"bigladder":0,"house":0,"chance":0,"yatzy":0,"totalsum":0}
self.spelarlista=[]
def __str__(self):
return self.name
def welcome(self):
print("Welcome to the yahtzee game!")
players = int(input("How many players: "))
rounds=0
while not players==rounds:
player=input("What is your name?: ")
rounds=rounds+1
self.spelarlista.append(Player(player))
print(self.spelarlista)
def main():
play=Player("Joakim")
play.welcome()
for key in ["names","ones","twos","threes","fours","fives","sixs","abovesum","bonus","onepair","twopair","threepair","fourpair","smalladder","bigladder","house","chance","yatzy","totalsum"]:
print("%-20s"%key)
main()
My goal is that its gonna look something like this: https://gyazo.com/26f997ed05c92898d93adaf0af57d024
If you look at my method "welcome", I do want to print my self.spelarlista, just to see how its gonna look, but all I get is "Player object at 0x7fac824....", I realize something is wrong with my str, how should I change it?
If you are getting Player object at 0x7fac824 or anything similar, it seems that you are calling the repr on the object (indirectly), which in turn calls the object's __repr__ method.
class Player:
# ...
def __repr__(self):
return self.name
# ...
Since there is no __str__ method defined, __str__ will also default to calling __repr__.
__repr__ returns a string representation of the object (usually one that can be converted back to the object, but that's just a convention) which is what you need.
When you print a list of objects python doesn't call the objects __str__ method but the container list. If you want to print them all you can call the __str__ method by applying the built-in function str() on them using map() or a list comprehension and join them with str.join() method.
print(' '.join(map(str, self.spelarlista)))
Or as another alternative approach you can define a __repr__ attribute for your objects, which returns the official string representation of an object:
>>> class A:
... def __init__(self):
... pass
... def __repr__(self):
... return 'a'
...
>>> l = [A()]
>>>
>>> print l
[a]
Related
class Freelencer:
company="google"
level=0
def upgradelevel(self):
self.level=self.level+1
class Employee:
company="visa"
ecode=120
class Programmer(Freelencer,Employee):
name="rohit"
p=Programmer()
p.upgradelevel()
print(p)
I want to print value of level is changed to 1. Below is the workflow of the code.
you are printing the object. you need to point "self.level".
print(p.level)
In either the Freelencer or Programmer class, you need to define a __str__ method that returns the string that should be shown when you print() the object. You could write a method as simple as this:
def __str__(self):
return 'level ' + str(self.level)
Then print(p) will show
level 1
You might need to override the print method in the Programmer class. use
def __repr__(self):
print(self.name) # or whatever you want to print
I would like to replace an object instance by another instance inside a method like this:
class A:
def method1(self):
self = func(self)
The object is retrieved from a database.
It is unlikely that replacing the 'self' variable will accomplish whatever you're trying to do, that couldn't just be accomplished by storing the result of func(self) in a different variable. 'self' is effectively a local variable only defined for the duration of the method call, used to pass in the instance of the class which is being operated upon. Replacing self will not actually replace references to the original instance of the class held by other objects, nor will it create a lasting reference to the new instance which was assigned to it.
As far as I understand, If you are trying to replace the current object with another object of same type (assuming func won't change the object type) from an member function. I think this will achieve that:
class A:
def method1(self):
newObj = func(self)
self.__dict__.update(newObj.__dict__)
It is not a direct answer to the question, but in the posts below there's a solution for what amirouche tried to do:
Python object conversion
Can I dynamically convert an instance of one class to another?
And here's working code sample (Python 3.2.5).
class Men:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a men! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_men(self):
print('I made The Matrix')
class Women:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a women! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_women(self):
print('I made Cloud Atlas')
men = Men('Larry')
men.who_are_you()
#>>> I'm a men! My name is Larry
men.method_unique_to_men()
#>>> I made The Matrix
men.cast_to(Women, 'Lana')
men.who_are_you()
#>>> I'm a women! My name is Lana
men.method_unique_to_women()
#>>> I made Cloud Atlas
Note the self.__class__ and not self.__class__.__name__. I.e. this technique not only replaces class name, but actually converts an instance of a class (at least both of them have same id()). Also, 1) I don't know whether it is "safe to replace a self object by another object of the same type in [an object own] method"; 2) it works with different types of objects, not only with ones that are of the same type; 3) it works not exactly like amirouche wanted: you can't init class like Class(args), only Class() (I'm not a pro and can't answer why it's like this).
Yes, all that will happen is that you won't be able to reference the current instance of your class A (unless you set another variable to self before you change it.) I wouldn't recommend it though, it makes for less readable code.
Note that you're only changing a variable, just like any other. Doing self = 123 is the same as doing abc = 123. self is only a reference to the current instance within the method. You can't change your instance by setting self.
What func(self) should do is to change the variables of your instance:
def func(obj):
obj.var_a = 123
obj.var_b = 'abc'
Then do this:
class A:
def method1(self):
func(self) # No need to assign self here
In many cases, a good way to achieve what you want is to call __init__ again. For example:
class MyList(list):
def trim(self,n):
self.__init__(self[:-n])
x = MyList([1,2,3,4])
x.trim(2)
assert type(x) == MyList
assert x == [1,2]
Note that this comes with a few assumptions such as the all that you want to change about the object being set in __init__. Also beware that this could cause problems with inheriting classes that redefine __init__ in an incompatible manner.
Yes, there is nothing wrong with this. Haters gonna hate. (Looking at you Pycharm with your in most cases imaginable, there's no point in such reassignment and it indicates an error).
A situation where you could do this is:
some_method(self, ...):
...
if(some_condition):
self = self.some_other_method()
...
return ...
Sure, you could start the method body by reassigning self to some other variable, but if you wouldn't normally do that with other parametres, why do it with self?
One can use the self assignment in a method, to change the class of instance to a derived class.
Of course one could assign it to a new object, but then the use of the new object ripples through the rest of code in the method. Reassiging it to self, leaves the rest of the method untouched.
class aclass:
def methodA(self):
...
if condition:
self = replace_by_derived(self)
# self is now referencing to an instance of a derived class
# with probably the same values for its data attributes
# all code here remains untouched
...
self.methodB() # calls the methodB of derivedclass is condition is True
...
def methodB(self):
# methodB of class aclass
...
class derivedclass(aclass):
def methodB(self):
#methodB of class derivedclass
...
But apart from such a special use case, I don't see any advantages to replace self.
You can make the instance a singleton element of the class
and mark the methods with #classmethod.
from enum import IntEnum
from collections import namedtuple
class kind(IntEnum):
circle = 1
square = 2
def attr(y): return [getattr(y, x) for x in 'k l b u r'.split()]
class Shape(namedtuple('Shape', 'k,l,b,u,r')):
self = None
#classmethod
def __repr__(cls):
return "<Shape({},{},{},{},{}) object at {}>".format(
*(attr(cls.self)+[id(cls.self)]))
#classmethod
def transform(cls, func):
cls.self = cls.self._replace(**func(cls.self))
Shape.self = Shape(k=1, l=2, b=3, u=4, r=5)
s = Shape.self
def nextkind(self):
return {'k': self.k+1}
print(repr(s)) # <Shape(1,2,3,4,5) object at 139766656561792>
s.transform(nextkind)
print(repr(s)) # <Shape(2,2,3,4,5) object at 139766656561888>
Here is the task: Write a class called LineUp.This class should contain
one (private) field (called acts) to store up to 30 acts. This field should be initialised in the constructor.
A method add_act that takes an Act (keep in mind I've written code above this with 'Act' and that's all fine) as an argument and adds it to acts if there are fewer than 30 acts already, otherwise a message “The festival is full!” should be printed,
add a method toString or str which produces a nice string with full line-up,
add a method print which prints a nice string with the full line-up.
I'm assuming that the first point is asking for a list. I think I've found a way to have a list in a class, but it has the same name (LineUp, as opposed to 'acts'). Here's what I have
class LineUp(list):
def __init__(self):
self.acts = []
def add_act():
if len(acts) >= 30:
print("The festival is full!")
else:
acts.append(Act)
def __str__(self):
string = "LineUp" + str(LineUp)
def println(self):
print(__str__(self))
Thanks in advance! Keep in mind this is my first draft.
EDIT: should I actually use a dictionary, not a list? Know that in another file I'm testing this code
You don't nee to inherit from list or get acts as parameter. To create a list for the class use self.acts in the constructor. You should also add __repr__
class LineUp:
def __init__(self):
self.acts = []
def add_act(self, act):
if len(self.acts) >= 30:
print("The festival is full!")
else:
self.acts.append(act)
def __repr__(self):
return f'LineUp{str(LineUp)}'
def __str__(self):
return f'LineUp{str(LineUp)}'
def println(self):
print(f'LineUp acts:{[act for act in self.acts]}')
Notice that str(LineUp) will return something like <class 'ExampleTest.LineUp'>, you might want to edit it.
class Ammo(Thing):
def __init__(self, name, weapon, quantity):
self.name=name
self.weapon=weapon
self.quantity=quantity
def get_quantity(self):
return self.quantity
def weapon_type(self):
return self.weapon
def remove_all():
self.quantity=0
bow = Weapon('bow', 10, 20)
arrows = Ammo('arrow', bow, 5)
print(arrows.weapon_type())
output of print(arrows.weapon_type()) is supposed to be bow but I got <__main__.Weapon object at 0x10441f0b8> instead. How can I modify my code so that it returns bow?
Below is class Weapon:
import random
class Weapon(Thing):
def __init__(self, name, min_dmg, max_dmg):
self.name=name
self.min_dmg=min_dmg
self.max_dmg=max_dmg
def min_damage(self):
return self.min_dmg
def max_damage(self):
return self.max_dmg
def damage(self):
return random.randint(self.min_dmg,self.max_dmg)
I think the best way to do it would be overriding the str function in Weapon.
adding:
def __str__(self):
return self.name
to your weapon class should fix it.
It depends on what do you want to print.
bow = Weapon('bow', 10, 20)
arrows = Ammo('arrow', bow, 5)
print(arrows.weapon_type())
The name of object:
bow = Weapon('bow', 10, 20)
# \_______ name of object
so you have to:
print(arrows.weapon_type().name)
# it will print bow
or your object itself:
bow = Weapon('bow', 10, 20)
# \____________________ object
I personally prefer print the name I passed in arguments, so if I call my object bow and pass "hardened_bow", 10, 20 as arguments it will print "hardened_bow" and not "bow"
Add repr to Weapon class:
def __repr__(self):
return self.name
object.__repr__(self)
Called by the repr() built-in function and by string conversions (reverse quotes) to compute the “official” string representation of an object. If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment).
If this is not possible, a string of the form <...some useful description...> should be returned. The return value must be a string object. If a class defines repr() but not str(), then repr() is also used when an “informal” string representation of instances of that class is required.
This is typically used for debugging, so it is important that the representation is information-rich and unambiguous.
object.__str__(self)
Called by the str() built-in function and by the print statement to compute the “informal” string representation of an object. This differs from __repr__() in that it does not have to be a valid Python expression: a more convenient or concise representation may be used instead. The return value must be a string object.
Reference
I'm trying to build a class that returns a dictionary when you call it. For instance this code:
class foobar():
def __init__(self):
self.Dictionary = {}
self.DictAddition()
def DictAddition(self):
self.Dictionary["Foo"] = "Bar"
def __repr__(self):
return repr([self.Dictionary])
When I call the class in my script like so will output class 'foobar.foobar'
Object = getattr(foobar, foobar)
Data = Object()
print(type(Data))
All tho I can print Data and it will print as expected a Dictionary, but I can't loop through the dictionary as it gives a TypeError, object is not iterable. Is there a way I can really return a type Dictionary from a class?
with kind regards,
So you want an object that behaves just like a dictionary, except for some special behavior that occurs during object creation? Sounds like an excellent time to use inheritance.
class foobar(dict):
def __init__(self):
super(foobar, self).__init__()
self["Foo"] = "Bar"
data = foobar()
print data
for item in data:
print "Item:", item
Result:
{'Foo': 'Bar'}
Item: Foo
Now, printing and iteration and everything else a dict can do, can also be done with your foobar class.
I must say I don't really understand what you are trying to do here: just making repr print a dictionary doesn't make your class one. But if you want to enable iteration for a class, you will need to override the __iter__ method.