Difference between print(*) and *.print() - python

I was staring at a very very long code. I am just trying the GUI part. There were these lines :
sh = packing_options[best_index].sheets[idx]
sh.print()
for rect in sh.rect_list:
rect.print()
I wanted to show the value stored in sh and rect for the GUI window.
When I use
b3 = tk.Label(top, text=sh)
b3.grid(row=0, column=2)
b4 = tk.Label(top, text=rect)
b4.grid(row=0, column=2)
It gives this as the result : <main.Sheet object at 0x0000024F5CF4A320>
The code for classes are given below:
class Rect:
def __init__(self, w, l):
self.l = l
self.w = w
def print(self):
print('Rect w:' + str(self.w) + 'l:' + str(self.l))
def area(self):
return self.l * self.w
## class for sheet to save all rectangles' positions
class Sheet:
# initialization
def __init__(self, W, L):
self.W = W # width (=horizontal length)
self.L = L # length (=height, vertical length)
self.rect_list = [] # rectangle list
self.rect_pos = [] # rectangle starting position from left bottom
self.rect_rotate = [] # rectangle rotation indicator list, 0: not rotated, 1: rotated
self.lhl_x = [0,W] # lowest horizontal line boundary point list
self.lhl_y = [0] # lowest horizontal line height list: each element is height
# area of sheet
def area(self):
return self.L * self.W
def print(self):
print('sheet W:' + str(self.W) + ' L:' + str(self.L))
How do I get the real value and store it in a variable to use print(*) (To use to show in GUI ultimately)

from itertools import enumerate
from tkinter import messagebox
def sheet_info(sheet):
str = "Sheet W:{} L:{} Contains {} rectangles:".format(sheet.W, sheet.L, len(sheet.rect_list))
for idx, rect in enumerate(sheet.rect_list):
str += "\n Rectangle W:{} L:{} at position {}".format(rect.w, rect.l, sheet.rect_pos[idx])
return str
messagebox.showinfo("sheet info", sheet_info(sh))
This should do it. May contain mistakes as i can't verify it atm.

Think of it as the behaviour of Python to print ing the object of a regular class , I.e if you provide the __str__ method it will print the object in stringified form with detail you are looking for (ofcourse you decide what is going to be printed) but if there is no __str__ method in the class, then printing an object will give you a queer output including address location of the object (similar to your example ) as standard print method does not know printing an object.
<__main__.Foobar instance at 0x7cf2a22e>
print(sh) is doing the same thing (nothing unexpected).
For this particular question both the print s are different .print is tkinter method defined on sh and print is python's method.
If you want to use the sh in python's built-in print function then you need to have a __str__ (or __repr__) method in the class Sheet , which will be the string representation of your object, because print(sh) finally invokes Sheet.__str__():
And in that __str__ method you can simply put all the details you wish to see on screen using the self keyword.
Very simple example in this direction will be
def __str__(self):
print('sheet W:' + str(self.W) + ' L:' + str(self.L))
__str__ is the string representation of an object and better think of it as toString function in Java (if you are familiar with it)

from tkinter import messagebox
messagebox.showinfo("Title", "your text here")

Related

How can I return the closest left and right child of a single node in simple binary tree?

I got a problem with my code, here it is : I want to return the closest left and right child of a node, but whenever I try to, it returns me ALL the children of this node.
I separated the code in two files, one contains the binary tree class (not BST, just a simple BT), and the other contains tkinter things, that suppose to show the node and his children. See below for the code, and sorry for some of the parts in french, if u need words to be translated i'm up.
binary tree file :
class ArbreBinaire:
def __init__(self, valeur):
self.valeur = valeur
self.enfant_gauche = None
self.enfant_droit = None
def __str__(self):
return f"{self.valeur}, ({self.enfant_gauche}, {self.enfant_droit})"
[enter image description here](https://i.stack.imgur.com/KJ3Gr.png)
def insert_gauche(self, valeur):
if self.enfant_gauche == None:
self.enfant_gauche = ArbreBinaire(valeur)
else:
new_node = ArbreBinaire(valeur)
new_node.enfant_gauche = self.enfant_gauche
self.enfant_gauche = new_node
def insert_droit(self, valeur):
if self.enfant_droit == None:
self.enfant_droit = ArbreBinaire(valeur)
else:
new_node = ArbreBinaire(valeur)
new_node.enfant_droit = self.enfant_droit
self.enfant_droit = new_node
def get_valeur(self):
return self.valeur
def get_gauche(self):
return self.enfant_gauche
def get_droit(self):
return self.enfant_droit
tkinter and main parts file :
from arb import ArbreBinaire
from tkinter import *
def classe_arb():
global racine, b_node, f_node, c_node, g_node, h_node
arb = ArbreBinaire
racine = ArbreBinaire('A')
racine.insert_gauche('B')
racine.insert_droit('F')
b_node = racine.get_gauche()
b_node.insert_gauche('C')
b_node.insert_droit('D')
f_node = racine.get_droit()
f_node.insert_gauche('G')
f_node.insert_droit('H')
c_node = b_node.get_gauche()
c_node.insert_droit('E')
g_node = f_node.get_gauche()
g_node.insert_gauche('I')
h_node = f_node.get_droit()
h_node.insert_droit('J')
return arb
def accueil():
global fenetre
fenetre = Tk()
fenetre.title("Bienvenue dans l'énigme du manoir")
fenetre.geometry("1000x500")
bt_jouer= Button(fenetre, text="Jouer", fg="green", command=lambda: valeur_bouton(1))
bt_jouer.pack()
bt_quitter = Button(fenetre, text="Quitter", fg="red", command=quit)
bt_quitter.pack()
fenetre.mainloop()
def jeu(phrase, rep1, rep2):
global run
run = True
while run == True:
global wd_jeu
wd_jeu = Tk()
wd_jeu.title("L'énigme du manoir")
wd_jeu.geometry("1000x500")
label = Label(wd_jeu, text=phrase, bg = "blue", fg = "white", font = "Castellar")
label.pack()
option1 = Button(wd_jeu, text=rep1, fg="black")
option1.pack()
option2 = Button(wd_jeu, text=rep2, fg="black")
option2.pack()
wd_jeu.mainloop()
def valeur_bouton(nb):
if nb == 0:
None
if nb == 1:
fenetre.destroy()
jeu('Hello', racine.valeur, racine.enfant_gauche)
classe_arb()
accueil()
Okay, so basically the problem is in the last function : "racine.valeur" and "racine.enfant_gauche". The first one works very well, it returns me the node with no problem. The second one "racine.enfant_gauche" is supposed to return the closest left child of the A node (B in this case), but it prints me all the children : "B, (C, (None, E, (None, None)), D, (None, None))".
I tried many things like this, like getting the value with the method "get_gauche" but it doesnt work as well. Thanks in advance for your help.
The __str__ method is called recursively because the format string f"{self.valeur}, ({self.enfant_gauche}, {self.enfant_droit})" will use the __str__ method of each child to resolve the embedded text.
To avoid the recursion, you could define method to get values of the left and right (e.g. valeur_gauche(), valeur_droite()) and use those instead in the format string. You could also get the values within your __str__ function and assemble the resulting string accordingly.
The expression racine.enfant_gauche evaluates to an instance of ArbreBinaire, and so when you pass it as argument to jeu and pass it to the Button constructor, the node's __str__ method will be called to retrieve the string that must be printed. This __str__ method will create a string representation that includes all descendants.
The expression racine.valeur on the other hand is a string (a single letter in your example), and so when you pass that to jeu, which passes it to the Button constructor, it will render as that string (as expected).
If you want the same behaviour for the left child, you should also take the .valeur attribute, like so:
jeu('Hello', racine.valeur, racine.enfant_gauche.valeur)

Issue using images in Python Tkinter

I am creating a Blackjack GUI game with Tkinter and I'm running into an issue where the deal button clears the image of the old card from the screen when a new one is added. My educated guess is the card_image inside the deal() function is overwriting itself when I use the function again. If this is the case why is this and what's the best fix? Thanks.
import random
from tkinter import *
from PIL import Image, ImageTk
root =Tk()
root.title('21 Blackjack')
root.iconbitmap('images/21_cards.ico')
root.geometry('1280x750')
root.configure(bg='green')
cards = []
suits = ['hearts', 'clubs', 'diamonds', 'spades']
face_cards = ['ace', 'jack', 'queen', 'king']
extension = 'png'
for y in suits:
for x in range(2, 11):
name = 'images/{}-{}.{}'.format(str(x), y, extension)
cards.append(name)
for x in face_cards:
name = 'images/{}-{}.{}'.format(str(x), y, extension)
cards.append(name)
print(cards)
print(len(cards))
random.shuffle(cards)
print(cards[0])
hand = []
def deal():
global card_image, card_label, hand
card_image = ImageTk.PhotoImage(Image.open(cards[0]).resize((180, 245), Image.ANTIALIAS))
card_label = Label(root, image=card_image, relief="raised").pack(side="left")
hand += cards[:1]
cards.pop(0)
print(hand)
deal_button = Button(root, text="deal", command=deal).pack()
root.mainloop()
Instead of
card_image = ImageTk.PhotoImage(Image.open(cards[0]).resize((180, 245), Image.ANTIALIAS))
card_label = Label(root, image=card_image, relief="raised").pack(side="left")
Do:
card_label = Label(root, image=card_image, relief="raised").pack(side="left")
card_image = ImageTk.PhotoImage(Image.open(cards[0]).resize((180, 245), Image.ANTIALIAS))
card_label.image = card_image #Keeps reference to the image so it's not garbage collected
Do note when you want use the photo use the variable card_image
As people have pointed out I needed to add card_label.image = card_image to the function and remove card_image & card_label global to stop the image being removed. But for some reason Python didn't like having the image being packed before I did this.
The function now looks like this.
global hand
card_image = ImageTk.PhotoImage(Image.open(cards[0]).resize((180, 245), Image.ANTIALIAS))
card_label = Label(root, image=card_image, relief="raised")
card_label.image = card_image
card_label.pack(side="left")
hand += cards[:1]
cards.pop(0)
print(hand)
You should use an image pool. Lucky for you, I have one right here
import os
from glob import glob
from PIL import Image, ImageTk
from typing import List, Tuple, Union, Dict, Type
from dataclasses import dataclass
#dataclass
class Image_dc:
image :Image.Image
rotate :int = 0
photo :ImageTk.PhotoImage = None
def size(self) -> Tuple[int]:
if not self.photo is None:
return self.photo.width(), self.photo.height()
return self.image.width, self.image.height
class ImagePool(object):
##__> PRIVATE INTERFACE <__##
__PATHS = dict()
__IMAGES = dict()
#staticmethod
def __name(path) -> str:
return os.path.basename(os.path.splitext(path)[0])
#staticmethod
def __unique(path:str, prefix:str='') -> str:
name = f'{prefix}{ImagePool.__name(path)}'
if name in ImagePool.names():
sol = 'using a prefix' if not prefix else f'changing your prefix ({prefix})'
msg = ("WARNING:\n"
f"{name} was not loaded due to a same-name conflict.\n"
f"You may want to consider {sol}.\n\n")
print(msg)
return None
return name
#staticmethod
def __request(name:str) -> Image_dc:
if name in ImagePool.__PATHS:
path = ImagePool.paths(name)
if os.path.isfile(path):
if name not in ImagePool.__IMAGES:
ImagePool.__IMAGES[name] = Image_dc(Image.open(path))
return ImagePool.__IMAGES[name]
else:
raise ValueError(f'ImagePool::__request - Path Error:\n\tpath is not a valid file\n\t{path}')
raise NameError(f'ImagePool::__request - Name Error:\n\t"{name}" does not exist')
return None
#staticmethod
def __size(iw:int, ih:int, w:int=None, h:int=None, scale:float=1.0) -> Tuple[int]:
if not w is None and not h is None:
if iw>ih:
ih = ih*(w/iw)
r = h/ih if (ih/h) > 1 else 1
iw, ih = w*r, ih*r
else:
iw = iw*(h/ih)
r = w/iw if (iw/w) > 1 else 1
iw, ih = iw*r, h*r
return int(iw*scale), int(ih*scale)
##__> PUBLIC INTERFACE <__##
#staticmethod
def names(prefix:str='') -> List[str]:
names = [*ImagePool.__PATHS]
return names if not prefix else list(filter(lambda name, pre=prefix: name.startswith(pre), names))
#staticmethod
def paths(name:str=None) -> Union[Dict, str]:
if name is None:
return ImagePool.__PATHS
if name in ImagePool.__PATHS:
return ImagePool.__PATHS[name]
raise NameError(f'ImagePool::paths - Name Error:\n\tname "{name}" does not exist')
#staticmethod
def images(name:str=None, prefix:str='') -> Union[Dict, Image.Image]:
if name is None:
return {name:ImagePool.__request(name).image for name in self.names(prefix)}
return ImagePool.__request(name).image
#staticmethod
def photos(name:str=None, prefix:str='') -> Union[Dict, ImageTk.PhotoImage]:
if name is None:
return {name:ImagePool.__request(name).photo for name in self.names(prefix)}
return ImagePool.__request(name).photo
#staticmethod
def append_file(path:str, prefix:str='') -> Type:
if not os.path.isfile(path):
raise ValueError(f'ImagePool::append_file - Value Error:\n\tpath is not valid\n\t{path}')
name = ImagePool.__unique(path, prefix)
if name:
ImagePool.__PATHS[name] = path
return ImagePool
#staticmethod
def append_directory(directory:str, filters=['*.png', '*.jpg'], prefix:str='') -> Type:
if not os.path.isdir(directory):
raise ValueError(f'ImagePool::append_directory - Value Error:\n\tdirectory is not valid\n\t{directory}')
filters = filters if isinstance(filters, (List, Tuple)) else [filters]
for filter in filters:
for path in glob(f'{directory}/{filter}'):
ImagePool.append_file(path, prefix)
return ImagePool
#staticmethod
def photo(name:str, width:int=None, height:int=None, scale:float=1.00, rotate:int=None) -> ImageTk.PhotoImage:
image_t = ImagePool.__request(name)
size = ImagePool.__size(*image_t.size(), width, height, scale)
rotate = image_t.rotate if rotate is None else rotate
#only resize if the new size or rotation is different than the current photo size or rotation
#however, a small margin for error must be considered for the size
diff = tuple(map(lambda i, j: i-j, image_t.size(), size))
if (diff > (1, 1)) or (diff < (-1, -1)) or (image_t.rotate != rotate):
image_t.rotate = rotate
image_t.photo = ImageTk.PhotoImage(image_t.image.resize(size, Image.LANCZOS).rotate(rotate))
return image_t.photo
Using that file you can do a lot of things very easily. You can put all your card images in a folder and get them all with:
ImagePool.append_directory(path_to_folder)
You can then get any card and force it to fit in it's parent (no-matter-what) with:
somelabel['image'] = ImagePool.photo(image_name, allotted_width, allotted_height)
or just:
somelabel['image'] = ImagePool.photo(image_name)
you can get a list of every name in the pool with
deck = ImagePool.names()
or grab it while you also append a directory
deck = ImagePool.append_directory(path_to_folder).names()
That is very helpful to you, because you can simply shuffle and pop that list as the official "deck" in your game. Like this:
somecard['image'] = ImagePool.photo(deck.pop(0))
Assuming you will have more than just card graphics, but do not want to get all the images when creating a deck, there is a solution for that, as well.
first supply a prefix when appending the cards image directory, and then use that prefix when calling names(). As long as only card images were in the cards image directory, only card names will be returned.
deck = ImagePool.append_directory(path_to_folder, prefix='cards_').names('cards_')
notes:
allotted area is only allotted and in no way should be assumed to represent the final width and/or height of the actual image. The image will do whatever it has to to fit in the allotted space without losing it's original height and width ratio. If you don't supply allotted width and height the image will be it's full size.
All image and photo references are automatically maintained in ImagePool. There is no reason to store your own references
The entire class is static so references to all the images and photos can be accessed anywhere without an ImagePool instance. In other words, you never need to do this: images = ImagePool() and therefore never need to figure out how to get images into some class or other document.
No images actually load until you start requesting them, and then it happens automatically. This is a good thing. You have 52 cards, but if you only use ex: 6 in the first game ~ only 6 will fully load. Eventually all the cards will get played and be fully loaded, and you didn't have some huge burp in your game where you tried to fully create 52 cards all at once.
The ImagePool class has more features, but the ones explained here are all you should need for your game.

Python Classes: Appending a list & Incorporating a Method

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

Why isn't self working in my code

I'm writing some code to create a toolbar that edits a map in ArcMap and I'm having some issues with getting variable values from other functions inside other classes that I'm using.
All the functions are predefined so I can't change the int arguments or the code will throw an error. I checked the dir() and none of the variables I define using self are in the functions. I don't think I've made a syntax error and the code inside the other classes works correctly.
Here is my code:
import arcpy
import math
import pythonaddins
class findingCoordinates(object):
"""Implementation for leetScripts_addin.tool (Tool)"""
def __init__(self):
self.enabled = True
self.shape = "NONE"
def onMouseDownMap(self, x, y, button, shift):
print "onMouseDowMap executing"
#this is where I declared the first two variables using self
self.x = x
self.y = y
print "Selected point is at %r, %r" % (self.x, self.y)
pass
class squareFeetInput(object):
"""Implementation for leetScripts_addin.combobox (ComboBox)"""
def __init__(self):
self.editable = True
self.enabled = True
#self.dropdownWidth = 'WWWWWW'
self.width = 'WWWWWW'
def onEditChange(self, text):
squareFeet = text
#this is the other variable I defined that I need to use later
self.buffDist = (math.sqrt(float(squareFeet))/2)
print "Square size: %r ft^2 Buffer Distance: %r ft^2" % (squareFeet,self.buffDist)
print "self.buffdist is a %r type" % self.buffDist
return self.buffDist
pass
class buildingTool(object):
"""Implementation for leetScripts_addin.button (Button)"""
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
print "building tool is executing"
#shows im_self, but no x or y
print "%r" % dir(findingCoordinates.onMouseDownMap)
# Get arguments:
# Input point feature class
# Output polygon feature class
# Buffer distance
# Boolean type: Maintain fields and field values of the input in the output
#This is where the problem is. I can't get these values from the previous functions.
inPoints = (findingCoordinates.onMouseDownMap.x,findingCoordinates.onMouseDownMap.y)
outPolys = "U:\JackBuildingFootprints.gdb\BuildingFootprintsCopy"
bufDist = squareFeetInput.buffDist
keepFields = true
# Prepare the output based on whether field and field values are desired in the output
#
if keepFields:
# Create empty output polygon feature class that includes fields of the input
#
arcpy.CreateFeatureClass(os.path.dirname(outPolys), os.path.basename(outPolys), "POLYGON",
inPoints, "", "", inPoints)
# Create a short list of fields to ignore when moving fields values from
# input to output
#
ignoreFields = []
# Use Describe properties to identify the shapeFieldName and OIDFieldName
#
desc = arcpy.Describe(inPoints)
ignoreFields.append(desc.shapeFieldName)
ignoreFields.append(desc.OIDFieldName)
# Create a list of fields to use when moving field values from input to output
#
fields = arcpy.ListFields(inPoints)
fieldList = []
for field in fields:
if field.name not in ignoreFields:
fieldList.append(field.name)
else:
# Create empty output polygon feature class without fields of the input
#
arcpy.CreateFeatureclass(os.path.dirname(outPolys), os.path.basename(outPolys), "POLYGON",
"", "", "", inPoints)
# Open searchcursor
#
inRows = arcpy.SearchCursor(inPoints)
# Open insertcursor
#
outRows = arcpy.InsertCursor(outPolys)
# Create point and array objects
#
pntObj = arcpy.Point()
arrayObj = arcpy.Array()
for inRow in inRows: # One output feature for each input point feature
inShape = inRow.shape
pnt = inShape.getPart(0)
# Need 5 vertices for square buffer: upper right, upper left, lower left,
# lower right, upper right. Add and subtract distance from coordinates of
# input point as appropriate.
for vertex in [0,1,2,3,4]:
pntObj.ID = vertex
if vertex in [0,3,4]:
pntObj.X = pnt.X + bufDist
else:
pntObj.X = pnt.X - bufDist
if vertex in [0,1,5]:
pntObj.Y = pnt.Y + bufDist
else:
pntObj.Y = pnt.Y - bufDist
arrayObj.add(pntObj)
# Create new row for output feature
#
feat = outRows.newRow()
# Shift attributes from input to output
#
if keepFields == "true":
for fieldName in fieldList:
feat.setValue(fieldName, inRow.getValue(fieldName))
# Assign array of points to output feature
#
feat.shape = arrayObj
# Insert the feature
#
outRows.insertRow(feat)
# Clear array of points
#
arrayObj.removeAll()
# Delete inputcursor
#
del outRows
pass
What am I doing wrong? Is this one of the rare occasions where I should use a global variable? Why is the directory not showing the variables I defined using self?
Edit:
I made this post a while ago and I just wanted to clear some things up now that I know more.
First:
This is code that is designed to be use with python_add_in. Python add in creates a toolbar based on some parameters you give it when you set it up, and whatever python code you put into a template it makes as a result of those parameters. That essentially means that all of the classes in the script above are events that occur when buttons and other toolbar objects are clicked or used in the toolbar.
Second:
The solution to this problem actually isn't in the accepted answer, my bad.
The root cause of the problem is that I was using class names that I declared in my script, findingCoordinates for example. python_add_in doesn't recognize these class names as the names of the classes it expects to receive based on the template you fill out before you start coding.
With that in mind, the issue was that I was trying to call classes that just didn't exist as far as python_add_in was concerned. The solution is to just go ahead and use the class names python_add_in tool expects you to use. These names are in the docstring located below the class definition so where I have findingCoordinates I should have Tool.
I hope this helps.
self refers to an instance of the class that you've defined, so to access those values, you need to create an instance of the class, call the method, and then access the values from the instance.
For example:
In [9]: %paste
class findingCoordinates(object):
"""Implementation for leetScripts_addin.tool (Tool)"""
def __init__(self):
self.enabled = True
self.shape = "NONE"
def onMouseDownMap(self, x, y, button, shift):
print "onMouseDowMap executing"
#this is where I declared the first two variables using self
self.x = x
self.y = y
print "Selected point is at %r, %r" % (self.x, self.y)
pass
## -- End pasted text --
In [10]: f = findingCoordinates()
In [11]: f.onMouseDownMap(x=1, y=2, button="button", shift="shift")
onMouseDowMap executing
Selected point is at 1, 2
In [12]: f.x
Out[12]: 1
In [13]: f.y
Out[13]: 2
EDIT: It seems like you've had some confusion about scoping/namespaces as well. There's no x or y defined globally; they just exist within the class instances. That will also allow you to have separate x and y values for different instances of the class.
In [14]: x
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-14-401b30e3b8b5> in <module>()
----> 1 x
NameError: name 'x' is not defined
In [15]: y
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-15-009520053b00> in <module>()
----> 1 y
NameError: name 'y' is not defined
In [16]: g = findingCoordinates()
In [17]: g.onMouseDownMap(100,200,0,0)
onMouseDowMap executing
Selected point is at 100, 200
In [18]: f.x, f.y
Out[18]: (1, 2)
In [19]: g.x, g.y
Out[19]: (100, 200)

Printing from within properties

I'm trying to make a robotics kit. Its designed to be simple so I'm using properties so when the users change a parameter the property method sends the serial command which controls motors/ servos/whatever.
This is the code at the moment, directly from a previous question I asked on here.
class Servo(object):
def __init__(self, which_servo, angle = 0):
self._angle = angle;
self._servo_no = which_servo
def get_angle(self):
return self._angle
def set_angle(self, value):
self._angle = value
print "replace this print statement with the code to set servo, notice that this method knows the servo number AND the desired value"
def del_angle(self):
del self._angle
angle = property(get_angle, set_angle, del_angle, "I'm the 'angle' property.
this is then initialized as such:
class robot(object):
def __init___(self):
self.servos = [Servo(0), Servo(1), Servo(2), Servo(3)]
Now, this works in the respect that it does change the variable through the getter and setter functions, however the prints in the getter and setter never is printed, thus if I replace it with a serial command I assume it won't do anything either, can anyone shed any light on this?
Thanks
Update: Thanks for the help using the servo file this is whats happened, there are three scenarios the first works and by extension I would have assumed the next two preferable scenarios would work but they don't any ideas?
This works
import servo
class Robot(object):
def __init__(self):
self.servos = [servo.Servo(0, 0), servo.Servo(1,0), servo.Servo(2,0)]
R = Robot()
R.servos[1].angle = 25
This does not:
import servo
class Robot(object):
def __init__(self):
self.servos = [servo.Servo(0, 0), servo.Servo(1,0), servo.Servo(2,0)]
R = Robot()
left_servo = R.servos[1].angle
left_servo = 25
Neither does this
import servo
class Robot(object):
def __init__(self):
self.servos = [servo.Servo(0, 0).angle, servo.Servo(1,0).angle, servo.Servo(2,0).angle]
R = Robot()
R.servo[1] = 25
Using the preferred decorator syntax for properties, this works fine. It'll also help you avoid issues like this in the future
class Servo(object):
def __init__(self, which_servo, angle = 0):
self._angle = angle;
self._servo_no = which_servo
#property
def angle(self):
return self._angle
#angle.setter
def angle(self, value):
self._angle = value
print "replace this print statement with the code to set servo"
#angle.deleter
def angle(self):
del self._angle
Seeing as your indentation is off here, I believe this is likely an issue of indentation in your source. This should work as well if you really want to use the old property function:
class Servo(object):
def __init__(self, which_servo, angle = 0):
self._angle = angle;
self._servo_no = which_servo
def get_angle(self):
return self._angle
def set_angle(self, value):
self._angle = value
print "replace this print statement with the code to set servo"
def del_angle(self):
del self._angle
angle = property(get_angle, set_angle, del_angle,"I'm the 'angle' property.")
Both of these work successfully for me (inside a file called servo.py)
>>> import servo
>>> s = servo.Servo(1, 2)
>>> s.angle
2
>>> s.angle = 3
replace this print statement with the code to set servo
EDIT
To address your new issues. When you assign R.servos[1].angle to left_servo, its not creating a reference to the servos angle, it's just setting left_servo to whatever the angle is. When you reassign 25 to it, you're not assigning to the angle you're assigning to the left_servo.
On the second one, I'm assuming you meant R.servos and not R.servo which should be raising an AttributeError. But the real problem as I see it, is you should be saying R.servos[1].angle = 25 and you're omitting the .angle.
To (attempt to) put it simply: When you use the = operator, you are changing where a name refers to, not what it refers to.
>>> x = 1
>>> x = 2
the second assignment does not overwrite the 1 in memory with a 2, it just changes where x refers to. So if I did something like
>>> x = 1
>>> y = x
>>> y = 2
>>> print x
1
the output is 1 because your are telling y to refer to the same place that x refers. Changing y to 2 changes where y refers to, it does not change the 1 already in memory.

Categories

Resources