Noah Clark
Noah Clark

Reputation: 8131

Object Attribute in Random List Not Accessible in Python

I'm working on my first object oriented bit of python and I have the following:

#!/usr/bin/python 
import random 

class triangle:

# Angle A To Angle C Connects Side F
# Angle C to Angle B Connects Side D
# Angle B to Angle A Connects Side E

    def __init__(self, a, b, c, d, e, f):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f

    #def solver:
        #pass

#initialize Triangle
myTri = triangle(0,0,0,0,0,0)

#Pick Three Random Angles or Sides to Generate Values For
sample = random.sample([myTri.a, myTri.b, myTri.c, myTri.d, myTri.e, myTri.f],  3)

#Sets the three randomly picked variables to a Random Number



sample[0] = random.randint(1, 100)
sample[1] = random.randint(1, 100)
sample[2] = random.randint(1, 100)

How do I pass myTri.a, for example to random.randint. It is passing the value of '0' which it initialized. I want to be able to assign a random value to three of the .a-.f attributes of myTri. What am I missing?

Upvotes: 1

Views: 420

Answers (3)

John Machin
John Machin

Reputation: 82934

Alternative to using setattr: do it when you create a Triangle instance.

args = [random.randint(1, 100) for i in xrange(3)] + [0, 0, 0]
random.shuffle(args)
my_tri = Triangle(*args)

Upvotes: 0

John Kugelman
John Kugelman

Reputation: 361710

When you say [myTri.a, myTri.b, ...] you are not getting a list of the variables themselves, or references to them. Instead you are getting just their values. Since you know they were initialized to 0, it is as if you had written [0, 0, 0, 0, 0, 0]. There's no difference.

Then later when you try to assign to sample[0], you are actually just overwriting the 0 that is stored in that array with a random value. Python knows nothing at all about myTri at that point; the connection is lost.

Here's what you can do to get the effect you're aiming for. First, pass a list of variable names we want to assign to later to random.sample:

sample = random.sample(["a", "b", "c", "d", "e", "f"], 3)

That'll give us back 3 random variable names. Now we want to assign to the variables with those same names. We can do that by using the special setattr function, which takes an object and a variable name and sets its value. For instance, setattr(myTri, "b", 72) does the same thing as myTri.b = 72. So rewritten we have:

setattr(myTri, sample[0], random.randint(1, 100))
setattr(myTri, sample[1], random.randint(1, 100))
setattr(myTri, sample[2], random.randint(1, 100))

The major concept here is that you're doing a bit of reflection, also known as introspection. You've got dynamic variable names--you don't know exactly who you're messing with--so you've got to consult with some more exotic, out of the way language constructs. Normally I'd actually caution against such tomfoolery, but this is a rare instance where introspection is a reasonable solution.

Upvotes: 5

Roger Pate
Roger Pate

Reputation:

To assign to a, b, and c:

myTri.a = random.randint(1, 100)
myTri.b = random.randint(1, 100)
myTri.c = random.randint(1, 100)

To assign to one random attribute from a-f:

attrs = ['a', 'b', 'c', 'd', 'e', 'f']
setattr(myTri, random.choice(attrs), random.randint(1, 100))

To assign to three random attributes from a-f:

attrs = ['a', 'b', 'c', 'd', 'e', 'f']
for attr in random.sample(attrs, 3):
  setattr(myTri, attr, random.randint(1, 100))

Upvotes: 2

Related Questions