This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
“Least Astonishment” in Python: The Mutable Default Argument
Default values for arguments
I'm having trouble explaining how a list belonging to a class behaves.
>>> class A(object):
... def __init__(self, L=[]):
... self.L = L
...
>>> a1 = A()
>>> a2 = A()
>>> a1.L.append("test")
>>> print a1.L
['test']
>>> print a2.L
['test']
In this example, how did a2.L get a value in it? I only added an item to the list in a1. How is it that they're sharing the list now.
Thanks,
Henry
A brief summary of all the comments you will get:
The problem is nothing to do with the class. It's because you're storing the values in the default argument of a function, and default arguments are stored on the function objects.
Related
This question already has answers here:
Understanding class type '__main__.ClassName'
(2 answers)
Closed 2 years ago.
I'm creating a class and checking the arguments for __init__.
class Example:
def __init__(self, a):
for key, val in locals().items():
print(type(val))
When I create this class, (something like Example(14)) I get <class '__main__.Example'> on the first line.
I know this is 'self', but what type is it?
The __main__ prefix is present because your class is defined in your script's global scope.
>>> class A:
... pass
...
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>>
The type of Example(14) is... well, Example, since that's the class of which that object is an instance.
This question already has answers here:
Python: Make class iterable
(6 answers)
Closed 2 years ago.
I'm wondering if it's possible to make a class object iterable in Python (ie. a subclass of type, NOT an instance of a class).
I've tried the following code:
class Foo:
#classmethod
def __iter__(cls):
yield 1
print(next(Foo.__iter__())) # prints 1
print(next(iter(Foo))) # TypeError: 'type' object is not iterable
Turns out it's possible with metaclasses.
class Foo(type):
def __iter__(self):
yield self.baz
class Bar(metaclass=Foo):
baz = 1
print(type(Bar)) # prints "<class '__main__.Foo'>"
print(next(Bar.__iter__())) # prints "1"
print(next(iter(Bar))) # prints "1"
Thanks #DanielB for pointing me in the right direction.
This isn't possible, as it would imply that all type objects are iterable - as you stated, classes are of type type. The underlying reason for this is that the __iter__ method is looked up on the type, not the value. E.g., in:
for i in Foo:
print(i)
Python will look up type(Foo).__iter__, not Foo.__iter__.
This question already has answers here:
How to use string value as a variable name in Python? [duplicate]
(3 answers)
How do I create variable variables?
(17 answers)
Closed 4 years ago.
let's say I have a variable called "x" and a string that has the value of "x" (string1 = "x"). How do I do stuff with the variable through the string?
For example change the variable's value or call a method if it's an object?
Thanks in advance
Variables are available through dictionaries locals() and globals(). If you want to access a particular variable by it's spring name, you can do e.g.
>>> my_var = 'hello'
>>> x = 'my_var'
>>> locals()[x]
'hello'
You can also assign back to the variable using this approach, e.g.
>>> my_var = 'hello'
>>> x = 'my_var'
>>> locals()[x] = 'something else'
>>> my_var
'something else'
Since functions are objects in Python, you can access any locally available functions in the same manner to call them.
>>> def my_test_function(n):
>>> return n*8
Accessing the method and calling it.
>>> locals()['my_test_function'](4)
32
For accessing attributes of objects by their name you can use getattr(), and setattr() to set them. For example, creating an object with a single property called your_prop.
class Example:
your_prop = 2
a = Example()
The value is available via your_prop.
>>> a.your_prop
2
The property can be accessed via name using getattr
>>> getattr(a, 'your_prop')
2
The property can be set using setattr:
>>> setattr(a, 'your_prop', 5)
>>> a.your_prop
5
Ok, let's suppose that you have lots of different functions: Aoo(), Boo(), Coo()... and let's suppose that you want to specify which of them to call via command line argument.
Now, that argument will be a string, so you need to call a function through its name, but you do not know in advance the name of the function.
One possible solution is to use exec():
def boo():
print("boo function")
def coo():
print("coo function")
Now:
argument = "boo"
exec(argument + "()")
>>> boo function
and
argument = "coo"
exec(argument + "()")
>>> coo function
It depends what you're trying to do, but you can scoop up whatever x is pointing to with locals() or globals():
def x(k):
return k + 1
string1 = "x"
the_function_x = locals()[string1]
print(the_function_x(3))
outputs 4 (it called the x function by utilizing string1).
This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 9 years ago.
I have a little problem that I do not understand.
I have a method:
def appendMethod(self, newInstance = someObject()):
self.someList.append(newInstace)
I call this method without attributes:
object.appendMethod()
And actually I append the list with the same instance of someObject.
But if I change it to:
def appendMethod(self):
newInstace = someObject()
self.someList.append(newInstance)
I get new instance of that object every time, what's the difference?
Here's an example:
class someClass():
myVal = 0
class otherClass1():
someList = []
def appendList(self):
new = someClass()
self.someList.append(new)
class otherClass2():
someList = []
def appendList(self, new = someClass()):
self.someList.append(new)
newObject = otherClass1()
newObject.appendList()
newObject.appendList()
print newObject.someList[0] is newObject.someList[1]
>>>False
anotherObject = otherClass2()
anotherObject.appendList()
anotherObject.appendList()
print anotherObject.someList[0] is anotherObject.someList[1]
>>>True
This is because you are assigning your default argument as a mutable object.
In python, a function is an object that gets evaluated when it is defined, So when you type def appendList(self, new = someClass()) you are defining new as a member object of the function, and it does NOT get re-evaluated at execution time.
see “Least Astonishment” in Python: The Mutable Default Argument
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
“Least Astonishment” in Python: The Mutable Default Argument
class Klass(object):
def a(self, d={}):
print d
self.b(d)
def b(self, d={}):
import random
print d
d[str(random.random())] = random.random()
I assumed that every time I call c.a() without arguments, I got a fresh empty dict. However, this is what actually happens:
>>> c = Klass()
>>> c.a()
{}
{}
>>> c.a()
{'0.637151613258': 0.61491180520119226}
{'0.637151613258': 0.61491180520119226}
>>> c.a()
{'0.637151613258': 0.61491180520119226, '0.960051474644': 0.54702415744398669}
{'0.637151613258': 0.61491180520119226, '0.960051474644': 0.54702415744398669}
...
I don't really want to do some sort of lambda/iscallable thing. What is a good pattern to use here?
Of course, I figured out I decent way around the problem by the time I had started typing out the question. But, if anyone has a different pet way around this, I would love to hear.
Could get a fresh, empty dict with:
def a(self, d=None):
if d is None:
d = {}
The problem is well described here under Mutable Default Arguments.