@adrius42 said:
Why??! This feels very counter-intuitive changing the meaning of equals in this way.
I guess way back in the mists of time the original Python developer had a reason!
So actually the operator was the time traveller! (Or rather the temporal cloner!)
IIRC, most languages do this. It allows some usefull stuff which would otherwise be impossible.
For example, assume you had the following code:
def add_defaults(l):
"""add some default values"""
if "value_default" not in l:
l.append("value_default")
def remove_invalid_values(l):
"""remove all invalid values from list"""
...
some_values = ask_user_for_input()
add_default_values(some_values)
remove_invalid_values(some_values)
print(some_values)
Due to having the same list shared between the functions, we can avoid unneccessary assignments. This is both easier and way more efficient.
But the more important reason is consistency: list are objects. This is the same in many programming languages due to the way they work. And all non-primitve objects (maybe there are some exceptions, but none important) are not directly assigned to a variable. Instead, when you say some_object = SomeObject(), SomeObject() is created somewhere in your RAM and a reference is created which points to SomeObject(). This reference is then assigned to some_object. When you use some_var = some_object, some_var actually gets a copy of the reference, like some_var = some_int would do, but the copy of the reference still points to the same object. Thus, even if some_var is a copy of the reference in some_object, it still points to the same object.
Maybe this code can explain this a bit better:
class SomeClass(object):
"""some class"""
def __init__(self, v):
v = v
int_var_a = 1 # int_var_a is directly assigned the integer 1
int_var_b = int_var_a # int_var_a is loaded, and the content is assigned to int_var_b
print(int_var_a == int_var_b) # True, both are equal
int_var_a = 2
print(int_var_a == int_var_b) # False
obj_var_a = SomeClass("value_1") # an instance of SomeClass() is created and stored in the RAM. A reference pointing to SomeClass() is created and assigned to obj_var_a
obj_var_b = obj_var_a # the >reference< if obj_car_a is copied to obj_var_b
print(obj_var_a.v == obj_var_b.v) # True, because both obj_var_* point to the same object
obj_var_b.v = "some other value" # the object is modified, but both obj_var_* still point to the same object
print(obj_var_a == obj_var_b) # True, because both obj_var_* still point to the same object and both have been modified
I am getting ever more convinced that I do not understand the operation of “self”
Can you point me to some text that would help me... it feels like self is not always self, and often self is “not defined’ when I know it had been!?
self is in fact not a operation, but a variable name without any real meaning.
Here is some more code:
class MyClass(object):
def method_a(self, x):
# self points to the instance of MyClass() this method is called on. x is some other value
pass
def method_b(foo, x):
# foo points to the instance of MyClass() this method is called on. x is some other value
# this is because the first parameter of a bound method is always the object
pass
@staticmethod
def some_static_method(x):
#This is a static method. self is not defined here. x is some other value passed to this method.
pass
@classmethod
def some_class_method(cls, x):
# This is a class method. cls is not pointing to the instance of the object this is called on, but instead pointing to the class this is called on.
# this is useful for alternative constructors
In other words: self is always defined if you name the first parameter/argument of a bound (more about that later) method self. If you name the first parameter/argument of a bound method foo, then foo would be the equivalent of self.
A bound method is a normal method of an instance of a class. In the above example, MyClass().method_a and MyClass().method_b are bound methods, because they are "normal" methods (not modified by @staticmethod or @classmethod) of an instance (MyClass()).
If you use MyClass.method_a or MyClass.method_b (please note the missing (), this is the class, not instances of the class), these are unbound methods, as they are not part of an instance. In this case, self must be specifically passed to the method.
Also, about self: you can think about self as some sort of namespace. self is unique per instance of a class. Changes to self persist between methods of the same instance, but not between methods of different instances.
I would have preferred
B = A transferred contents of A to B just thus once
B == A results in B becoming the same as A for all time
In python, == means a comparsion of equality.
But then I am just wishing that the Python Language understood me, rather than me having to understand it!
Dont worry, you are not the only one...
To be clear this only applies to lists right?
A = 1
B = A
A = 2
Won’t change B to 2
So, are there any other types of variables where the operators change what they do?
This behavior applies to all non-primitive types.
Some example of primitive types are int, long and float.
Non-primitive types are basically everything else, mostly instances of classes.
So, a={}; b=a; b["a"] = 2 would also modify a.
a=1; b=a; b=2 would not change a, because both b and a are primitive.
Strings are interesting. They are objects, but immutable. a=""; b=a; some_change(b) would change a too, but since neither a nor b can be changed, this is not a problem.
Small disclaimer: I am not involved with the development of python and can thus not guarantee that the above information is correct, but it should be.
Sorry for my bad english, it is not my native language. I still hope that this may be of help for you.