0

Dynamic Attribute Access in Python?

I was working on a small side programming project I decided to undertake and ran into an error that I wasn't sure how to solve... I have searched for answers but really I only ever am finding results that seem to be inapplicable to this specific scenario (or maybe I am not searching for the right thing...). Here is the code I am trying to run (not including the full program, it is too long):

def Bet(percent):
    Screen = screenGrab()
    print 'betting ' + percent
    if (Screen.getpixel(Cord.percent) == Colors.percent_button):
        mousePos(Cord.percent)
        leftClick()
        time.sleep(.05)
        leftClick()
        BetNum = RNDORG.IntegerGenerator(1, 101)
        if (BetNum < 51):
            print 'Betting Left'
            mousePos(Cord.Comp_Left)
            leftClick()
            time.sleep(.05)
            leftClick()

        if (BetNum >= 51):
            print 'Betting Right'
            mousePos(Cord.Comp_Right)
            leftClick()
            time.sleep(.05)
            leftClick()
        #(later maybe) calculate best option,click on a percent, click on a competitior

When I run the program in python command prompt I get this error:

Perecentage to bet? (format it as P_%, to go all in type ALLIN)P_10
bettingP_10

Traceback (most recent call last):
  File "C:\Users\\Documents\Documents\Documents\PythonSaltyBot\SaltyBasicBot.py", line 148, in <module>
    main()
  File "C:\Users\\Documents\Documents\Documents\PythonSaltyBot\SaltyBasicBot.py", line 141, in main
    Bet(UPercent)
  File "C:\Users\\Documents\Documents\Documents\PythonSaltyBot\SaltyBasicBot.py", line 112, in Bet
    if (Screen.getpixel(Cord.percent) == Colors.percent_button):
AttributeError: class Cord has no attribute 'percent'

The most troublesome part for me is that python seems to interpret the percent parameter as literally the command "percent," not what was actually passed to it (in this case P_10 as shown by the print statement). I have a way of handling what is passed through the bet() function and limiting it to only arguments that I have a Cord parameter for, I just am unsure how to get python to not interpret "percent" as "percent" in the command call:

if (Screen.getpixel(Cord.percent) == Colors.percent_button):

So basically I am asking how I can use this parameter to invoke a method(if thats even possible...)? Do I need to turn it into a string or something? If its not possible how could I interpret the parameter to send it up to the Cord method?

I am relatively new to programming, and something tells me this is not something I should be attempting or there should be another way around it. I thought about creating a sort of Switch statement for each case (similar to http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html), but I felt what I currently have is much more efficient.

Heres the code I use to pre-filter what is passed to the parameter:

UPercent = raw_input('Perecentage to bet? (format it as P_%, to go all in type ALLIN)')
if (UPercent == ('P_10' or 'P_20' or 'P_30' or 'P_40' or 'P_50' or 'P_60' or 'P_70' or 'P_80' or 'P_90' or 'ALLIN')):
    Bet(UPercent)

Thanks, any response is appreciated!


Alright heres the solved code (I also fixed the "if ... ==" statement, but that wasn't what I asked about) ...:

def Bet(percent):
    Screen = screenGrab() 
    if (Screen.getpixel(getattr(Cord, percent)) == Colors.percent_button):
        #Check bets-----------------------------------------------------------------
        print 'betting ' + percent
        mousePos(getattr(Cord, percent))
        leftClick()
        time.sleep(.05)
        leftClick()
        BetNum = RNDORG.IntegerGenerator(1, 101)
        if (BetNum < 51):
            print 'Betting Left'
            mousePos(Cord.Comp_Left)
            leftClick()
            time.sleep(.05)
            leftClick()

        if (BetNum >= 51):
            print 'Betting Right'
            mousePos(Cord.Comp_Right)
            leftClick()
            time.sleep(.05)
            leftClick()
        #(later maybe) calculate best option,click on a percent, click on a competitior

And heres to clarify what cord and colors are:

class Cord:
    Comp_Left = (730,(ymax-140)-y_pad)
    Comp_Right = (1190,(ymax-140)-y_pad)
#CompLeftValue = (,)
#CompRightValue = (,)
    TextBox = (864, 767)
    P_10 = (220,(ymax-50)-y_pad) #button centers seem to have a 160-170 pixel interval, .085 rati
    P_20 = (380,(ymax-50)-y_pad) #60 is the distance from the bottom of the screen to the buttons
    P_30 = (540,(ymax-50)-y_pad) #on the windows operating system, so y max -60 will always give
    P_40 = (710,(ymax-50)-y_pad) #the approximate y coordinate
    P_50 = (870,(ymax-50)-y_pad)
    P_60 = (1030,(ymax-50)-y_pad)
    P_70 = (1200,(ymax-50)-y_pad)
    P_80 = (1370,(ymax-50)-y_pad)
    P_90 = (1530,(ymax-50)-y_pad)
    AllIN = (1710,(ymax-50)-y_pad)
    TEST = (221,912)

class Colors:
    percent_button = (100, 65, 165)
    background = (26, 26, 26)
    left_button = (176, 68, 68)
    right_button = (52, 158, 255)

I hope this helps anyone who had the same problem, this was a frustrating issue for me.

Starman
  • 19
  • 5
  • 2
    Python most definitely does NOT interpret a variable's name as its value. It really is very unclear what your problem is, and what you are trying to accomplish. – wroniasty Jul 22 '14 at 15:18
  • `Cord.percent` means: find the object referenced by the name `Cord`, then retrieve the attribute `percent` from that object. You *have* an object named `Cord` (it references a class), but that object has no such attribute. – Martijn Pieters Jul 22 '14 at 15:25
  • See [How do I test one variable against multiple values?](http://stackoverflow.com/q/15112125) for your pre-filter test; the expression you have does **not** do what you think it does. – Martijn Pieters Jul 22 '14 at 15:26
  • 1
    And I **suspect** that you are looking for dynamic attribute access; `getattr(Cord, percent)`, but your question is *very unclear*. – Martijn Pieters Jul 22 '14 at 15:27
  • What is `Cord`, and what are you trying to do by `Cord.percent`? – interjay Jul 22 '14 at 15:28
  • By the way, `if (UPercent == ('P_10' or 'P_20' or 'P_30' or 'P_40' or 'P_50' or 'P_60' or 'P_70' or 'P_80' or 'P_90' or 'ALLIN'))` does not work like you think. You need to use `in`. – interjay Jul 22 '14 at 15:29
  • Sorry, Cord is a class containing several (X, Y) coordinate values, I am basically telling the program take a screenshot, check the color of the button is active, and then act based on if the button is active or not. If I used just "percent" nothing would have since the method requires (X, Y) coordinates as parameters, and "percent" (the data stored in the parameter tag percent) is not an (X, Y) Coordinate. – Starman Jul 22 '14 at 15:39
  • Tried to make it as clear as possible, I guess I should have added something about what cord is. I wasn't sure if it was necessary or not. I'm not sure why "==" would not work, it was working fine.. only thing I can think of is logical operations versus bitwise. I wrote it so that it would scan through all of those and say is it equal to this one, this one... until it reached a conclusion. – Starman Jul 22 '14 at 15:45
  • Also How else was I supposed to ask this question? I didn't know dynamic attribute access existed before you mentioned it. None of the tutorials I looked at even mentioned it: https://docs.python.org/2/tutorial/controlflow.html, http://anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/functions.html I even put what I was trying to ask in BOLD what else am I supposed to do? – Starman Jul 22 '14 at 17:37

1 Answers1

1

The syntax Cord.percent does not mean *get the attribute named in percent from Cord; it just means get the attribute named percent from Cord.

To dynamically access attributes, use the getattr() function:

getattr(Cord, percent)

Now Python will dereference percent, and retrieve the attribute named in it from Cord.

Note that your filter expression:

UPercent == ('P_10' or 'P_20' or 'P_30' or 'P_40' or 'P_50' or 'P_60' or 'P_70' or 'P_80' or 'P_90' or 'ALLIN')

will not work, use:

UPercent in ('P_10', 'P_20', 'P_30', 'P_40', 'P_50', 'P_60', 'P_70', 'P_80', 'P_90', 'ALLIN')

instead. See How do I test one variable against multiple values?

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • It worked! Thankyou! Did not know about that function, I guess I was looking more at basics of passing parameters than at the functions you could use with parameters. – Starman Jul 22 '14 at 15:35