is there any difference between these two method?
option1 :
class a(object):
def __init__(self):
self.x = 123
self.y = 345
option2 :
class a(object):
x = 123
y = 345
is there any difference between these two options?
Thanks in advance.
An example of the first method (instance level variables):
instance0 = a()
instance1 = b()
instance0.x = 5
print instance1.x # prints 123
print a.x # undefined variable - x is not defined
An example of the second method (class level variables):
instance0 = a()
instance1 = b()
instance0.x = 5
print instance1.x # prints 5
print a.x # prints 5
The second method, the variables are assigned at the class level meaning changing this value propagates to all instances of that class. You can also access the variables without an instance of the class.
Yes, in the first case each object of class a has its own copy of x and y, in the second case all objects of class a share them.
By the way, if your starting out with Python, use a capital for the first character of your class names, e.g. MyClass. People are used to that and it will help you understand your own programs once they get bigger.
Related
Is there any way to get this to work?
class A:
def method(self):
x = 5
y = 2
method.z = x * y
class B(A):
def method(self):
super().method()
z = super().method().z
xyz = 2**z
def main():
a = A().method()
b = B().method()
main()
Running it gives
NameError: name 'method' is not defined
The idea is that the super class does preliminary work that all subclasses would need to perform, and passes the result on to the subclass for use (in this case z).
Because the data is only needed in the scope of the subclass method calls, it doesn't make sense to store it in the scope of the class as an instance variable.
The above code is using notation found here, in search of C static function variables in python.
This question already has answers here:
Is accessing class variables via an instance documented?
(2 answers)
Closed 6 years ago.
I'm trying to grasp on the idea on how the class variables work. And to my knowledge class variables are shared between the class instances (objects).
So within THAT idea, if I change the class variable, the value should change to all the class instances...
...BUT, this seems not to be always the case.
Below is an simplified example:
class A:
name = "Dog"
a1 = A()
a2 = A()
# These both change the value only for an instance
a1.name = "Cat"
a2.name += " is an animal"
print(a1.name, a2.name)
class B:
number = 0
b1 = B()
b2 = B()
# Again only changes value for an instance
b1.number = 2
print(b1.number, b2.number)
# This is the weird one.
class C:
lista = []
c1 = C()
c2 = C()
# Changes the value for BOTH/ALL instances.
c1.lista.append(5)
c2.lista.append(6)
print(c1.lista, c2.lista)
# But this one only changes the value for an instance.
c1.lista = [1, 2, 3]
print(c1.lista, c2.lista)
Class variables are shared between instances until the moment you assign to an instance variable by the same name. (As an aside, this behavior is useful for declaring defaults in inheritance situations.)
>>> class X:
... foo = "foo"
...
>>> a = X()
>>> b = X()
>>> c = X()
>>> c.foo = "bar"
>>> id(a.foo)
4349299488
>>> id(b.foo)
4349299488
>>> id(c.foo)
4349299824
>>>
Your list example mutates the shared instance first, then reassigns a new value to c1.lista, but c2.lista remains the shared instance.
I am new to python and i am not sure how this is working. Code is as below:
class test():
d=0
def __init__(self):
self.d=self.d+1;
D=test()
print D.d
D1=test()
print D1.d
D2=test()
print D2.d
Output is
1,1,1 # This should not be
Now using this :
class test():
d=[]
def __init__(self):
self.d.apend("1");
D=test()
print D.d
D1=test()
print D1.d
D2=test()
print D2.d
Result is (This should be)
['1']
['1', '1']
['1', '1', '1']
So i am not sure why integer value is not being treated as class variable while list is being treated.
In the first example,
self.d = self.d + 1
rebinds self.d, making it independent of test.d.
In the second example,
self.d.append("1")
modifies test.d.
To see that for yourself, print id(self.d) at the end of both constructors.
If you modified the second example to match the first:
self.d = self.d + ["1"]
you'd see that the behaviour would also change to match.
If you want to modify a class variable, do:
class test(object):
d=0
def __init__(self):
type(self).d=self.d+1;
D=test()
print D.d
D1=test()
print D1.d
D2=test()
print D2.d
You don't need the type on the right hand side of the assignment, because this way you never create an instance variable d. Note that new-style classes are necessary to this.
type is a function (actually a callable - it is also a class; but don't worry about that for now) which returns the class of its argument. So, type(self) returns the class of self. Classes are first class objects in Python.
Demo here: http://ideone.com/JdNpiV
Update: An alternative would be to use a classmethod.
To address a class variable use class_name.variable_name, giving :
class test(object):
d=0
def __init__(self):
test.d = test.d + 1;
NPE's answer tells you what is going wrong with your code. However, I'm not sure that it really tells you how to solve the issue properly.
Here's what I think you want, if each test instance should have a different d value in an instance variable:
class test(object): # new style class, since we inherit from "object"
_d = 0 # this is a class variable, which I've named _d to avoid confusion
def __init__(self):
self.d = test._d # assign current value of class variable to an instance variable
test._d += 1 # increment the class variable
Now, you can create multiple instances and each one will get a unique value for d:
>>> D0 = test()
>>> D1 = test()
>>> D2 = test()
>>> print D0.d
0
>>> print D1.d
1
>>> print D2.d
2
This should be simple...
class Object:
x = 0
y = []
a = Object()
b = Object()
a.x = 1
b.x = 2
print a.x, b.x
# output: 1 2
# works as expected
a.y.append(3)
b.y.append(4)
print a.y, b.y
# output: [3, 4] [3, 4]
# same list is referenced how to fix?
# desired output: [3] [4]
As far as I can tell, a.y and b.y reference the same list. How can I get them to be separate? Preferably, without adding an __init__ method.
You're creating the value of y only once, when you define the class. To assign a different list to each instance of y, you do need an init function. Just put self.y = [] in __init__ and it will work as intended.
What's happening here is that you actually have actually redefined x as an instance level attribute, and your class definition had them as both class level attributes.
If you do this, you can see your original x is still at 0.
>>> Object.x
0
As you don't create a new list, it's taking the class attribute. If you were to do this:
>>> a.y = []
>>> b.y = []
>>> a.y.append(1)
>>> b.y.append(2)
>>> print a.y, b.y
[1] [2]
That is what you are expecting. Really though you should be defining your class like this:
class Object(object):
def __init__(self):
self.y = []
self.x = 0
(and don't use Object as a classname!)
The easiest way to setup instance properties instead of class properties is to use __init__
When you reference an instance property (like a.y) the parser tries to return that first but if it isn't found the class property (Object.y) is returned.
In your case only defined a class property which is shared by all instances.
The only way to do that is creating the __init__ method
class Object:
def __init__(self):
self.x = 0
self.y = []
That way upon Object's construction, a new value will be assined to x and a new List will be created for y.
The way you were doing before creates two class/static variables to Object, but only y stays the same because it holds statically only a reference to the true List, reflecting to all instances of Object.
More on class/static variables on this other question:
Static class variables in Python
*Sorry if I used the wrong terms, I'm more of a Java person ;-)
This question already has answers here:
Override a method at instance level
(11 answers)
Closed 3 years ago.
I do not know python very much (never used it before :D), but I can't seem to find anything online. Maybe I just didn't google the right question, but here I go:
I want to change an instance's implementation of a specific method. When I googled for it, I found you could do it, but it changes the implementation for all other instances of the same class, for example:
def showyImp(self):
print self.y
class Foo:
def __init__(self):
self.x = "x = 25"
self.y = "y = 4"
def showx(self):
print self.x
def showy(self):
print "y = woohoo"
class Bar:
def __init__(self):
Foo.showy = showyImp
self.foo = Foo()
def show(self):
self.foo.showx()
self.foo.showy()
if __name__ == '__main__':
b = Bar()
b.show()
f = Foo()
f.showx()
f.showy()
This does not work as expected, because the output is the following:
x = 25
y = 4
x = 25
y = 4
And I want it to be:
x = 25
y = 4
x = 25
y = woohoo
I tried to change Bar's init method with this:
def __init__(self):
self.foo = Foo()
self.foo.showy = showyImp
But I get the following error message:
showyImp() takes exactly 1 argument (0 given)
So yeah... I tried using setattr(), but seems like it's the same as self.foo.showy = showyImp.
Any clue? :)
Since Python 2.6, you should use the types module's MethodType class:
from types import MethodType
class A(object):
def m(self):
print 'aaa'
a = A()
def new_m(self):
print 'bbb'
a.m = MethodType(new_m, a)
As another answer pointed out, however, this will not work for 'magic' methods of new-style classes, such as __str__().
This answer is outdated; the answer below works with modern Python
Everything you wanted to know about Python Attributes and Methods.
Yes, this is an indirect answer, but it demonstrates a number of techniques and explains some of the more intricate details and "magic".
For a "more direct" answer, consider python's new module. In particular, look at the instancemethod function which allows "binding" a method to an instance -- in this case, that would allow you to use "self" in the method.
import new
class Z(object):
pass
z = Z()
def method(self):
return self
z.q = new.instancemethod(method, z, None)
z is z.q() # true
If you ever need to do it for a special method (which, for a new-style class -- which is what you should always be using and the only kind in Python 3 -- is looked up on the class, not the instance), you can just make a per-instance class, e.g....:
self.foo = Foo()
meths = {'__str__': lambda self: 'peekaboo!'}
self.foo.__class__ = type('yFoo', (Foo,), meths)
Edit: I've been asked to clarify the advantages of this approach wrt new.instancemethod...:
>>> class X(object):
... def __str__(self): return 'baah'
...
>>> x=X()
>>> y=X()
>>> print x, y
baah baah
>>> x.__str__ = new.instancemethod(lambda self: 'boo!', x)
>>> print x, y
baah baah
As you can see, the new.instancemethod is totally useless in this case. OTOH...:
>>> x.__class__=type('X',(X,),{'__str__':lambda self:'boo!'})
>>> print x, y
boo! baah
...assigning a new class works great for this case and every other. BTW, as I hope is clear, once you've done this to a given instance you can then later add more method and other class attributes to its x.__class__ and intrinsically affect only that one instance!
If you're binding to the instance, you shouldn't include the self argument:
>>> class Foo(object):
... pass
...
>>> def donothing():
... pass
...
>>> f = Foo()
>>> f.x = donothing
>>> f.x()
>>>
You do need the self argument if you're binding to a class though:
>>> def class_donothing(self):
... pass
...
>>> foo.y = class_donothing
>>> f.y()
>>>
Your example is kind of twisted and complex, and I don't quite see what it has to do with your question. Feel free to clarify if you like.
However, it's pretty easy to do what you're looking to do, assuming I'm reading your question right.
class Foo(object):
def bar(self):
print('bar')
def baz():
print('baz')
In an interpreter ...
>>> f = Foo()
>>> f.bar()
bar
>>> f.bar = baz
>>> f.bar()
baz
>>> g = Foo()
>>> g.bar()
bar
>>> f.bar()
baz
Do Not Do This.
Changing one instance's methods is just wrong.
Here are the rules of OO Design.
Avoid Magic.
If you can't use inheritance, use delegation.
That means that every time you think you need something magic, you should have been writing a "wrapper" or Facade around the object to add the features you want.
Just write a wrapper.