1

This is a follow up from my last question as to why the setattr within a class for a method did not work and I found an answer on it but now I have a small problem with it

class Test:
    def myString(self, var):
        Test.myString.string = var
        return self.myString

I then do this

x = Test()
x.myString("test").string

It returns test but then I try this

y = list()
[y.append(x.myString(str(i))) for i in range(10)]

then try to get the list by doing this, [j.string for j in y] and it returns 9 total digits of nine. Is their a way to fix this so it appends the number it's currently on?

4
  • Didnt you get AttributeError: 'instancemethod' object has no attribute 'string'? Commented Dec 1, 2013 at 3:39
  • 1
    @thefourtheye: the OP must be using 3.X. Commented Dec 1, 2013 at 3:40
  • Yes, I am using python3.3.3 sorry that I did not clarify that Commented Dec 1, 2013 at 3:44
  • Is there a problem that you are trying to solve with this? There probably is a better way. Commented Dec 1, 2013 at 5:05

2 Answers 2

1

This is a really weird design. I suspect there's a more natural way to do whatever this is trying to do.

That said, what's going on is that your myString method sets values on the class method itself. I see from your previous question (Can you set an attribute to a method in python) that calling the bound method creates a new instance of the bound method each time, so you are actually getting different objects returned from your successive calls to the myString method, but you're always updating a single value on the class's unbound method object. In general, if you're setting data on a class rather than an instance you're setting that data for all instances of the class.

I can't figure out what you're trying to do here. Obviously you could trivially get a list of the string representations of 0-9, but clearly there's something more required.

A much more natural design is just to set the string on the class instances - but it's so simple and straightforward it's actually hard to demonstrate.

class Test:
    pass

x = Test()
x.string = 'one'
print(x.string)

So, again, I can only assume you're looking for something more involved.

Sign up to request clarification or add additional context in comments.

6 Comments

I'm trying to get it to append 9 objects with the digits 0-9 like you said only I want to be able to call on them like [variable.string for variable in listHere] in my ass it would by [j.string for j in y] I do know however [str(i) for i in range(10)] would give me the same result but I am not after that
If you want 9 objects, where do you plan to instantiate the 9 different objects? You could easily do so in a list comprehension, but in your example code you just instantiate x once. That said, your posted code directly alters data on the class itself (Test.myString.string) so with this code it doesn't matter how many instances you have - they don't track string themselves, they all set it on the class. Which is part of the weirdness of the design.
I'm really struggling with why you want to have attributes on the method at all, as opposed to just member data in the object.
@ruler: Why do you want attributes on the method? That's a very weird place to put your data.
Hopefully this will help understand why I want this to work: pastebin.com/5rKWz168
|
0

I found two ways to do what I needed here they are for anyone that was confused or didn't know how to do this either basically I wanted to create an entire new object rather than using the same one since when I called on it it used it's last data and thats why it didn't work before so using a lambda or class seemed to work fine but if anyone else has a different way of doing this let me know.

# Option One
class Test:
    def myString(self, string):
        newObject = lambda: None
        setattr(newObject,"string", string)
        return newObject
myTest = Test()
myList = list()
[myList.append(myTest.myString(str(i))) for i in range(10)]
[attr.string for attr in myList] # Output: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

# Option Two
class newObject: pass

class Test:
    def myString(self, string):
        newObj = newObject()
        setattr(newObj,"string", string)
        return newObj
myTest = Test()
myList = list()
[myList.append(myTest.myString(str(i))) for i in range(10)]
[attr.string for attr in myList] # Output: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

3 Comments

I'm glad you figured out a solution that works for you, but this still makes no sense to me. These two approaches are both unnecessarily complex compared to just putting the strings directly into a list. Or if you want arbitrary attribute names other than string, save a dictionary for each string. That's basically all an empty class like your version two is.
@Peter Thanks, but yeah this is just some example code. The actual code makes sense for this type of stuff see here I am aware that using the position then a list index would work for that also but I'd rather use names like obj.variable than listHere[number]
Does that pastebin code accurately represent your actual use case? It can be improved but there's not much point if it too is very simplified.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.