I'm trying to make a chopsticks game. Here's a wikipedia link to the game https://en.wikipedia.org/wiki/Chopsticks_(hand_game). So far I just added a couple methods so that one hand can attack another hand using the 'attack' method. I feel like the code I wrote is very verbose, ugly and maybe even wrong though. How can I write this more elegantly?
class game:
def __init__(self):
self.x_left = 1
self.x_right = 1
self.o_left = 1
self.o_right = 1
def set_x_left(self, num):
self.x_left = num
def set_x_right(self, num):
self.x_right = num
def set_o_left(self, num):
self.o_left = num
def set_o_right(self, num):
self.o_right = num
def dict_func(self, hand):
self.func= {'x_left': self.set_x_left, 'x_right': self.set_x_right,
'o_left': self.set_o_left, 'o_right': self.set_o_right}
return self.func[hand]
def dict_hand(self, hand):
self.hands = {'x_left': self.x_left, 'x_right': self.x_right,
'o_left': self.o_left, 'o_right': self.o_right}
return self.hands[hand]
def attack(self, from_hand, to_hand):
self.dict_func(to_hand)(self.dict_hand(from_hand) + self.dict_hand(to_hand))
your code seems to have some unnecessary methods. You can get rid of the methods that set the variables with a number:
def set_x_left(self, num):
self.x_left = num
When you create an instance of game you can use dot notation to set the values:
chopsticks = game()
# ^^^ that's the instance
chopsticks.set_x_left(0)
# is the same as
chopsticks.x_left = 0
As you can see it's quicker to type, doesn't require any methods. It's just attribute assignments. Doing this will affect you dict_func method, so you can create an anonymous function instead:
def dict_func(self, hand):
self.func = {'x_left': lambda self, x: self.x_left = x,
'x_right': lambda self, x: self.x_right = x,
'o_left': lambda self, x: self.o_left = x,
'o_right': lambda self, x: self.o_right = x}
return self.func[hand]
In fact you can declare the self.func self.hands attributes in __init__ to make sure that they're only assigned to once. Then in the function you can just write return self.func[hand]
Your dict_hand method is also slightly over complicated. Your aim is to get the attribute from the instance dict, so you can do:
def dict_hand(self, hand):
return getatttr(self, hand)
(You may want to rename this function :))
Related
I have a class containing a list and some boolean methods.
class Cls:
data = [] // populated in __init__()
def flag1(self):
def flag2(self):
def flag3(self): # these all return booleans, based on the data
I want to create a higher level function, taking a parameter one of the flags, manipulating the data in a number of ways, applying the flag to the new data, and counting the number of results.
Something like:
def hof(self, fn):
count = 0
for i in range(1, 10):
new_obj = Cls(self.data+i)
if new_obj.fn():
count +=1
Is there any way to accomplish this without turning all the flags into static methods ?
===
Edit: Made it work, in a very hackish way:
class Cls:
data = []
def __init__(self):
self.data = value
class flag1(self):
return True
class flag2(self):
return False
# The hackish part
flag_dict = {
1: flag1,
2: flag2,
}
def hof(self, flag):
count = 0
for i in range(1,10):
new_obj = Cls(self.data + [i])
if self.flag_dict[flag](new_obj):
count +=1
return count
But it seems like a hack, and it's not quite understandable. Could someone point to a better way ?
Thanks.
You should be able to just pass the methods into the function like instance.hof(Cls.flag1), and internally, write it as if fn(new_obj):, with no need to make it a staticmethod.
I just started learning about Python classes today and I had a quick question. I'm pretty amazed how much more succinct it has made my code, but I'm trying to figure out if the following is possible for a chess problem I'm working on.
(1) Can I append a list somehow from within a class method? I'm trying to figure out if there's a way to accumulate the pieces in a list each time capture is called.
(2) How can I call a method from within the class to be used in another method? I would like to be able to check if a move is valid before even proceeding if the piece should try to capture another or move.
class Piece(Board):
def __init__(self, piece, r, c):
self.piece = piece
self.r = r
self.c = c
This is the function I would like to incorporate into the functions below to avoid the redundancy (Question 2)
def valid_move(self,r,c,r_offset,c_offset):
#r, c are integers for the coordinates on the board
#r_offset,c_offset are the cells the piece might move to
self.tgt_r, self.tgt_c = r+r_offset, c+c_offset
if self.tgt_r <= 7 or self.tgt_c >= 0:
return True
return False
These functions are the same for now. I'm trying to see how I can use the capture function to accumulate a list of pieces once they're taken. (Question 1)
def capture(self,r,c, r_offset, c_offset):
piece = self.piece
self.tgt_r, self.tgt_c = r+r_offset, c+c_offset
if self.tgt_r > 7 or self.tgt_c < 0:
return None
else:
nb = Board(curr).copy_board() #this board is just 8x8 np.array
nb[self.tgt_r,self.tgt_c], nb[r,c] = piece,'-'
return nb
def move(self,r,c, r_offset, c_offset):
piece = self.piece
self.tgt_r, self.tgt_c = r+r_offset, c+c_offset
if self.tgt_r > 7 or self.tgt_c < 0:
return None
else:
nb = Board(curr).copy_board()
nb[self.tgt_r,self.tgt_c], nb[r,c] = piece,'-'
return nb
Thanks as always.
1. Can I append a list somehow from within a class method?
create a list -piecesList in your class for storing the pieces:
class Piece(Board):
def __init__(self, piece, r, c):
self.piece = piece
self.r = r
self.c = c
self.piecesList = [] #or init using some argument if you want to use some list from outside of the class
and whenever your capture method is called, simply append the piece in the piecesList :
def capture(self,r,c, r_offset, c_offset):
self.piecesList.append(self.piece)
piece = self.piece
2. How can I call a method from within the class to be used in another method?
you can simply call it using self.method(arg1, arg2...) :
def capture(self,r,c, r_offset, c_offset):
piece = self.piece
if self.valid_move(r,c,r_offset,c_offset) == False:
return None
else:
nb = Board(curr).copy_board() #this board is just 8x8 np.array
nb[self.tgt_r,self.tgt_c], nb[r,c] = piece,'-'
return nb
class Time:
def __init__(self,x,y,z):
self.hour=x
self.minute=y
self.second=z
def __str__(self):
return "({:02d}:{:02d}:{:02d})".format(self.hour, self.minute, self.second)
def time_to_int(time):
minutes=time.hour*60+time.minute
seconds=minutes*60+time.second
return seconds
def int_to_time(seconds):
time=Time()
minutes,time.second=divmod(seconds,60)
time.hour,time.minute=divmod(minutes,60)
return time
def add_time(t1,t2):
seconds=time_to_int(t1)+time_to_int(t2)
return int_to_time(seconds)
start=Time(9,45,00)
running=Time(1,35,00)
done=add_time(start,running)
print(done)
I am new to python and i've been doing some practice lately.I came across a question and i've written the code for the same.But I am repeatedly getting an error: "add_time is not defined". I tried defining a main() method but then it doesn't print anything.Please help.
You haven't created an object to the above class.
Any function/method inside a class can only be accessed by an object of that class .For more information on the fundamentals of Object Oriented Programming, please check this page.
Meanwhile for this to work, define your class in the following way :
class Time:
def __init__(self,x=None,y=None,z=None):
self.hour=x
self.minute=y
self.second=z
def __str__(self):
return "({:02d}:{:02d}:{:02d})".format(self.hour, self.minute, self.second)
def time_to_int(time):
minutes=time.hour*60+time.minute
seconds=minutes*60+time.second
return seconds
def int_to_time(seconds):
time=Time()
minutes,time.second=divmod(seconds,60)
time.hour,time.minute=divmod(minutes,60)
return time
def add_time(t1,t2):
seconds=time_to_int(t1)+time_to_int(t2)
return int_to_time(seconds)
and outside the class block, write the following lines :
TimeObject = Time()
start=Time(9,45,00)
running=Time(1,35,00)
TimeObject.add_time(start,running)
print "done"
I however suggest you to write the add_time function outside the class because you are passing the objects to the class as the parameters to the function within the same class and it is considered as a bad design in object oriented programming.
Hope it helps. Cheers!
This works fine for me as long as you specified 3 args in your constructor
def int_to_time(seconds):
time=Time(0,0,0) # just set your 3 positionals args here
minutes,time.second=divmod(seconds,60)
time.hour,time.minute=divmod(minutes,60)
return time
Another way to avoid it could be:
class Time:
def __init__(self,x=0,y=0,z=0):
self.hour=x
self.minute=y
self.second=z
If you want to add your functions to your class (such as time_to_int, int_to_time or even add_time) then you will need to indent with one more level of 4 spaces and add self to your method parameters
Hii Mathers25,
I solve your problem try this below code to get the best output,
class TimeClass:
def __init__(self,x,y,z):
self.hour = x
self.minute = y
self.second = z
def __str__(self):
return "({:02d}:{:02d}:{:02d})".format(self.hour, self.minute, self.second)
def time_to_int(self,time):
minutes = (time.hour * 60) + time.minute
seconds = (minutes * 60) + time.second
return seconds
def int_to_time(self,seconds):
time = TimeClass(0,0,0)
minutes,time.second=divmod(seconds,60)
time.hour,time.minute=divmod(minutes,60)
return time
def add_time(self,t1,t2):
seconds = self.time_to_int(t1) + self.time_to_int(t2)
# Call method int_to_time() using self keyword.
return self.int_to_time(seconds)
# First time object create that time set value is 0 of hour,minute and second
TimeObject = TimeClass(0,0,0)
# After create second object
start=TimeClass(9,45,00)
# After create thired Object
running=TimeClass(1,35,00)
# Store the value which return by add_time()
done = TimeObject.add_time(start,running)
# Display the value of done variable
print(done)
class Employee:
def __init__(self):
self.wage = 0
self.hours_worked = 0
def calculate_pay(self):
return self.wage * self.hours_worked
alice = Employee()
alice.wage = 9.25
alice.hours_worked = 35
print('Alice:\n Net pay: {:.2f}'.format(alice.calculate_pay()))
barbara = Employee()
barbara.wage = 11.50
barbara.hours_worked = 20
print('Barbara:\n Net pay: {:.2f}'.format(barbara.calculate_pay()))
Works for me:
class C:
def f(a, b):
return a + b
x = f(1,2)
print(C.x)
but you should not do such things. Code in class-level is executing when class is "creating", usually you want static methods or class methods (decorated with #staticmethod or #classmethod) and execute code in some function/instantiated class. Also you can execute it on top (module) level if this is the simple script. Your snippet is "bad practice": class level (i'm talking about indentation) is for declarations, not for execution of something. On class-level is normal to execute code which is analogue of C macros: for example, to call decorator, to transform some method/attribute/etc - static things which are "pure" functions!
So I'm designing a hangman game using Python and Kivy and I want to add a win/lose option.
one of the functions I've defined is Button_pressed which hides the button if it's been pressed but I want the function man_is_hung() to have something that says "if the button has been pressed 6 times, show "game over"."
Would someone please help me?
def button_pressed(button):
for (letter, label) in CurrentWord:
if (letter.upper() == button.text): label.text=letter
button.text=" " # hide the letter to indicate it's been tried
def man_is_hung():
if button_pressed(button)
Use a decorator:
Example:
class count_calls(object):
def __init__(self, func):
self.count = 0
self.func = func
def __call__(self, *args, **kwargs):
# if self.count == 6 : do something
self.count += 1
return self.func(*args, **kwargs)
#count_calls
def func(x, y):
return x + y
Demo:
>>> for _ in range(4): func(0, 0)
>>> func.count
4
>>> func(0, 0)
0
>>> func.count
5
In py3.x you can use nonlocal to achieve the same thing using a function instead of a class:
def count_calls(func):
count = 0
def wrapper(*args, **kwargs):
nonlocal count
if count == 6:
raise TypeError('Enough button pressing')
count += 1
return func(*args, **kwargs)
return wrapper
#count_calls
def func(x, y):
return x + y
Demo:
>>> for _ in range(6):func(1,1)
>>> func(1, 1)
...
raise TypeError('Enough button pressing')
TypeError: Enough button pressing
You could store the button as a class like so:
class button_pressed(Object):
def __init__(self):
self.num_calls = 0
def __call__(self, button):
self.num_calls += 1
if self.num_calls > 6:
print "Game over."
return None
else:
# Your regular function stuff goes here.
This is basically a manual decorator, and while it might be a bit complicated for what you are trying to do this is an easy way to do bookkeeping on a function.
Really, the correct way to do this kind of thing is to use a decorator that takes a parameter for the number of times you want the function to be able to be called and then applies the above pattern automatically.
Edit: Ahh! hcwhsa beat me to it. His solution is the more general one I was talking about above.
Here's a way to have static variables in functions that doesn't involve globals or classes:
def foobar():
foobar.counter = getattr(foobar, 'counter', 0)
foobar.counter += 1
return foobar.counter
for i in range(5):
print foobar()
ummmm
num_presses = 0
def button_pressed(button):
global num_presses
num_presses += 1
if num_presses > X:
print "YOU LOSE SUCKA!!!"
for (letter, label) in CurrentWord:
if (letter.upper() == button.text): label.text=letter
button.text=" " # hide the letter to indicate it's been tried
would be one way of doing it ... Im kind of suprised you have made it this far without knowing how to save simple states.
I am maintaining a little library of useful functions for interacting with my company's APIs and I have come across (what I think is) a neat question that I can't find the answer to.
I frequently have to request large amounts of data from an API, so I do something like:
class Client(object):
def __init__(self):
self.data = []
def get_data(self, offset = 0):
done = False
while not done:
data = get_more_starting_at(offset)
self.data.extend(data)
offset += 1
if not data:
done = True
This works fine and allows me to restart the retrieval where I left off if something goes horribly wrong. However, since python functions are just regular objects, we can do stuff like:
def yo():
yo.hi = "yo!"
return None
and then we can interrogate yo about its properties later, like:
yo.hi => "yo!"
my question is: Can I rewrite my class-based example to pin the data to the function itself, without referring to the function by name. I know I can do this by:
def get_data(offset=0):
done = False
get_data.data = []
while not done:
data = get_more_starting_from(offset)
get_data.data.extend(data)
offset += 1
if not data:
done = True
return get_data.data
but I would like to do something like:
def get_data(offset=0):
done = False
self.data = [] # <===== this is the bit I can't figure out
while not done:
data = get_more_starting_from(offset)
self.data.extend(data) # <====== also this!
offset += 1
if not data:
done = True
return self.data # <======== want to refer to the "current" object
Is it possible to refer to the "current" object by anything other than its name?
Something like "this", "self", or "memememe!" is what I'm looking for.
I don't understand why you want to do this, but it's what a fixed point combinator allows you to do:
import functools
def Y(f):
#functools.wraps(f)
def Yf(*args):
return inner(*args)
inner = f(Yf)
return Yf
#Y
def get_data(f):
def inner_get_data(*args):
# This is your real get data function
# define it as normal
# but just refer to it as 'f' inside itself
print 'setting get_data.foo to', args
f.foo = args
return inner_get_data
get_data(1, 2, 3)
print get_data.foo
So you call get_data as normal, and it "magically" knows that f means itself.
You could do this, but (a) the data is not per-function-invocation, but per function (b) it's much easier to achieve this sort of thing with a class.
If you had to do it, you might do something like this:
def ybother(a,b,c,yrselflambda = lambda: ybother):
yrself = yrselflambda()
#other stuff
The lambda is necessary, because you need to delay evaluation of the term ybother until something has been bound to it.
Alternatively, and increasingly pointlessly:
from functools import partial
def ybother(a,b,c,yrself=None):
#whatever
yrself.data = [] # this will blow up if the default argument is used
#more stuff
bothered = partial(ybother, yrself=ybother)
Or:
def unbothered(a,b,c):
def inbothered(yrself):
#whatever
yrself.data = []
return inbothered, inbothered(inbothered)
This last version gives you a different function object each time, which you might like.
There are almost certainly introspective tricks to do this, but they are even less worthwhile.
Not sure what doing it like this gains you, but what about using a decorator.
import functools
def add_self(f):
#functools.wraps(f)
def wrapper(*args,**kwargs):
if not getattr(f, 'content', None):
f.content = []
return f(f, *args, **kwargs)
return wrapper
#add_self
def example(self, arg1):
self.content.append(arg1)
print self.content
example(1)
example(2)
example(3)
OUTPUT
[1]
[1, 2]
[1, 2, 3]