views:

183

answers:

3

Hello.

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?

+1  A: 

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))
Roger Pate
This works, but doesn't work for my application as I don't want to set just the first three.
NoahClark
Could you read the rest of the answer?
Roger Pate
For some reason I couldn't. It makes sense now! Is there any reason to do this over the previous poster?
NoahClark
Previous? Mine was posted first by 1 minute. :P We both have the same answer, using setattr(), the differences are superficial.
Roger Pate
Okay, I assumed they were superficial, but I'm to the point now where I really want to learn python and really understand what's going on instead of hacking my way through it. Sorry, you're correct, you were 1 minute faster!
NoahClark
+5  A: 

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.

John Kugelman
+1  A: 

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)
John Machin