0

I have a class, and I created two instances of it ,object1 and object2, I addend an attribute to each called "number", I want to be able to choose to which class I apply a function that I have created to change the "number"attribute, I managed to create the function but when i execute it only does it at a local level in the function, it does not return the result to the original object1.number instance, I assumne the problem is in how I positioned my variables.

So i want my global object1.number attribute to be changed inside the number_changer function and then be able to see that change outside the function.

I have used the print function along the code to follow the process, and it seems to do well, just its unable to change the global attribute

class ClassA():    
    pass


object1 = ClassA()    
object1.number = "0"    
object2 = ClassA()    
object2.number = "1"    


current_object = "object1"    
x = input("new number ")    

print(object1.number)    


def number_changer(object_name,new_number):    
    variable = object_name + ".number"    
    global object1    

    ref_obj_list = ["object1.number", "object2.number"]    
    real_obj_list = [object1.number, object2.number]    
    count = -1    
    for item in ref_obj_list:    
        count += 1    
        if variable == item:    
            real_obj_list[count]  = new_number    
            d = real_obj_list[count]    

            return d    




print(number_changer(current_object,x))    

print(object1.number)    

when I put the number "5" in the input the result is this

0    
5    
0    

the object1.number attribute does not change or at least not in a global level

lmiguelvargasf
  • 63,191
  • 45
  • 217
  • 228
  • I'm calling "x/y problem" on this question. What problem are you trying to solve with this indirect code? You manipulate object attributes outside the class. You go out of your way to hard-code an indirect relationship between each object and the name of the variable. You hand-code your own indexing loop. You can bypass virtually all of this with `object1.number = input("new number ")`. – Prune Sep 11 '19 at 20:13
  • @PatrickArtner I want to change the number attribute of my objects, but I will not always know which object I will change the attribute, the purpose of the function is to detect the object an then change it. – Diego Vente Seminario Sep 11 '19 at 20:15
  • @Prune I cant do that , because I will not always know the object to be changed, the variable "current_object" will also be an input, that kinda of be generated randomly, thats what the function does, find the object to change the attribute. – Diego Vente Seminario Sep 11 '19 at 20:17
  • ... You are only replacing the value inside your local list inside your function with a string - nothing modifies the original ClassA() instances numbers ... – Patrick Artner Sep 11 '19 at 20:18
  • 1
    I'm still confused as to the interface design -- you're requiring that the user know all of your internal variable names, a clear violation of interface practices. What problem are you solving with this? – Prune Sep 11 '19 at 20:21
  • See the addendum to my answer regarding attributes. You are probably looking for a dictionary to choose your instances by user input. The design is flawed though - why should your users know some kind of internal name for your instances ... – Patrick Artner Sep 11 '19 at 20:24

4 Answers4

2

In Python, objects are passed by reference, so if you change any attribute of that object inside a function/method, it will be changed no matter if you use global or not.

The problem I am seeing in your logic is that you are never changing the value of the attribute, you should do something as:

object1.number = 123 # this is going to change that attribute no matter if you use the global keyword
lmiguelvargasf
  • 63,191
  • 45
  • 217
  • 228
2

Most of your code is superflous. If you pass an object to a function and access a non-existing attribute you get an error. If you set an attribute it will create it if not existing or change it if already existing:

class A:
    pass 


a1 = A()
a2 = A()

def changer(o,newtext):
    try:
        o.text = o.text + newtext
    except AttributeError:            # happens if the attribute does not exist
        print(".text does not exist")

a1.text = "whatever"
a2.text = "never"

print(a1.text, a2.text)  # prints whats being set
changer(a1,"changed")    # changes a1.text
print(a1.text, a2.text)  # prints changed text

changer(A(),"hallo")  # prints the caught/handled exception - A() has no .text

Output:

whatever never
whateverchanged never
.text does not exist

The "normal" way to do this would be to simpy add text to the class:

class A:
    def __init__(self):
        self.text = None

that way it exists all the time and is unique to each instance.

See What is the difference between class and instance attributes? for explanation of instance and (shared) class attributes


To select an object by user input, use a dictionary:

myAs = {"A1":a1, "A2":a2}   # a1,a2 from above

print(a1.text, a2.text)    
whichOne = input("Which element to change? " +  repr(list(myAs.keys())))
if whichOne in myAs:
    changer( myAs[whichOne],"YeHaa")
    print(a1.text, a2.text)

Output:

whateverchanged never
Which element to change? ['A1', 'A2'] A2
whateverchanged neverYeHaa
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • Thanks your code helped me a lot, Im just learning so I really dont uderstand the whole picture. These user inputs i want it to be deliver to the program later, like from an API, Im unsure on how that works. – Diego Vente Seminario Sep 11 '19 at 21:14
  • Here is the code I wanted it, as you said is some kind of dictionary , so i dont know the object to change, My final code is at the end – Diego Vente Seminario Sep 11 '19 at 21:15
0

In your function, by using this line:

real_obj_list[count]  = new_number  

you are not changing the actual object's value, you are just changing the value in the real_obj_list array.

I don't see what's wrong with using a simple assignment:

object1.number = 1

(which is nowhere to be seen in your function, hence the value is not updating).

But if you want a function for it, @PatrickArtner's answer pretty much sums it up.

Anis R.
  • 6,656
  • 2
  • 15
  • 37
0

If I change the value of current_object it will change the attribute as desired, want I wanted was to be able to choose in which object I will apply the attribute changer, that was why I could not use the direct way, thanks a lot.

current_object = "a"    
def matcher(object):    
    ref_list = ["a","b","c"]    
    real_list = [a,b,c]    
   count = -1    
    for item in ref_list:    
        count += 1    
        if item == object:    
            d = real_list[count]    
            return d    


class A():    
    pass    

a = A()    
b = A()    
c = A()    

var = matcher(current_object)    

def changer(o,newtext):    
    o.text =  newtext    

a.text = "bye"    
b.text = "hello"    
c.text = "Dunno"    

print(a.text)    
print(b.text)    
print(c.text)    

changer(var,"works")    

print(a.text)    
print(b.text)    
print(c.text)