Why I have 2 after second call? - python

class s:
i = []
def inc():
t = s()
t.i.append(len(t.i))
return len(t.i)
print(inc())
print(inc())
my output:
1
2
but I expected:
1
1
becouse everytime created new object, where my mistake?

You are appending to a variable of the class, not a variable of the instance
class s:
i = []
This code creates a variable in the class. This is similar to the concept of a static variable in Java or C++.
In java:
class S {
static List i = new ...
}
You probably wanted to do this:
class s:
def __init__(self):
self.i = []
This creates a variable in the instance, which is named self (similar to this in Java or C++). __init__ is the constructor of the class.

You should make i instance variable
class s:
def __init__(self):
self.i = []

You have made i a variable of the class itself.
If you want a variable for each class instance use self
class s:
def __init__(self):
self.i = []

You need to modify the instance variable:
class s:
def __init__(self):
self.i = []
def inc():
t = s()
t.i.append(len(t.i))
return len(t.i)
You are now modifying the same list of class s and hence it increments from 1 to 2.

Try making i an instance variable.
class s:
def __init__(self):
self.i = []

Related

Why #property broke synchronizing with source object on proxy class

I want to create a proxy in Python because of function and attributes access (something like private). I create the proxy with references to functions in the source object. But I have a problem, that functions have no problem with changing attributes but property yes. Here is an example:
A working example
class A:
def __init__(self):
self.value = 1
def get_value(self):
return self.value
class Proxy:
def __init__(self, cls):
self.get_value = cls.get_value
# del cls
a = A()
p = Proxy(a)
print(a.get_value(), p.get_value())
a.value = 2
print(a.get_value(), p.get_value())
Output:
1 1
2 2
Not working:
class A:
def __init__(self):
self.value = 1
#property
def get_value(self):
return self.value
class Proxy:
def __init__(self, cls):
self.get_value = cls.get_value
# del cls
a = A()
p = Proxy(a)
print(a.get_value, p.get_value)
a.value = 2
print(a.get_value, p.get_value)
Output:
1 1
2 1
Can someone explain me where the problem is and if there is any solution for this? I could use functions, but I think #property is more Python solution. And I really want to know what is the difference. Thank you
In Proxy.__init__, you end up executing:
self.get_value = a.get_value
and very different things happen in your two examples.
In the first case, a.get_value is a method of a. So, calling p.get_value() is the same as calling a.get_value(). You get identical results.
In the second case, you have already defined a.get_value as a property, so self.get_value = a.get_value is basically self.get_value = 2, it is just an int attribute of p.

get object on which a method was called in Python

Is there a way in Python to get a reference to an object on which a method was called?
And in case it is, is it possible even in a nested way?
my_class.py:
from modules import math_ops
class A():
def __init__(self):
self.math_ops = math_ops.B()
self.number = 1
modules/math_ops.py:
class B():
def add_1():
where_to_add = # Get instance of A() object
where_to_add.number += 1
To execute this:
>>> a = A()
>>> a.math_ops.add_1()
And get this:
>>> a.number
2
I'm asking because I am interested in writing a static method which works with the object on which it was called, but would like to avoid using the object as an argument as it would be much nicer to call a method like my_object.prop.static_method() instead of my_object.prop.static_method(my_object).
If you never plan on reassigning math_ops outside A, this is fairly simple to do.
from modules import math_ops
class A():
def __init__():
self.math_ops = math_ops.B(self)
self.number = 1
modules/math_ops.py:
class B():
def __init__(self, creator):
self.creator = creator
def add_1():
creator.number += 1
I will mention it again in case you skimmed the first line, the following will generate unexpected results since B is tracking the creator of the object rather than the caller.
a1 = A()
a2 = A()
a1.math_ops = a2.math_ops
a1.math_ops.add_1() # a2 is updated
If that looks like something you might wanna do, the answer is a tad more complicated. Here's my attempt:
from modules import math_ops
class A():
def __init__(self):
self._math_ops = math_ops.B(self)
self.number = 1
#property
def math_ops(self):
self._math_ops.set_caller(self)
return self._math_ops
#math_ops.setter
def math_ops(self, new_math_ops):
self._math_ops = new_math_ops
modules/math_ops.py:
class B():
def __init__(self, caller):
self.caller = caller
def set_caller(self, caller):
self.caller = caller
def add_1(self):
self.caller.number += 1
class A():
number = 1
class B():
def add_1():
where_to_add = A
where_to_add.number += 1
B.add_1()
print(A.number)
B.add_1()
print(A.number)
B.add_1()
print(A.number)

How do I use a static variable inside a class in Python

class Cls:
counter = 0
def __init__(self, name):
self.name = name
self.counter += 1
def count(self):
return self.counter
I'm learning python, what I want to have is a static counter that counts the number of times the class has been instantiated, but every time I create an instance counter gets recreated and count() function always returns 1.
I want something that in java would look like this
public class Cls {
private static int counter = 0;
private String name;
public Cls(String name) {
this.name = name;
counter ++;
}
public static int count(){
return counter;
}
}
There are two ways to access a class attribute: you can either access it directly on a class, or you can read it through self (but not rebind it). Accessing a class attribute through self won't work if there is already a value set directly on the instance so you would normally try to use the class to access a class attribute.
class Cls:
counter = 0
def __init__(self, name):
self.name = name
Cls.counter += 1
def count(self):
return Cls.counter
When you write self.counter += 1 this is a shorthand for self.counter = self.counter + 1 and as with any other binding through self it sets an instance attribute.
This can be useful if you want a default value for instance attributes, you can set them as class attributes and then just update them in the instances which want different values, but to avoid confusion you probably want to avoid using self at all when accessing class attributes.
You can also consider making the count method into a class method and moving the increment into another method:
#classmethod
def increment(cls):
cls.counter += 1
#classmethod
def count(cls):
return cls.counter
if you do that then each subclass will have its own independent counter. That may or may not be what you want here. The cls parameter here is the class that was actually instantiated, this can be useful if you can a whole class hierarchy, or even just a base class CountsInstances where you can put this code once and reuse it with multiple independent counters.
Decorating each function with #staticmethod will give you something close to the Java code:
class Cls:
counter = 0
def __init__(self, name):
self.name = name
self.increment()
#staticmethod
def increment():
Cls.counter += 1
#staticmethod
def count():
return Cls.counter
Do not use Cls.
class MyClass:
counter = 0
def __init__(self, name):
self.name = name
self.counter += 1 # this creates an instance variable counter
# thats initialized by counter if you do not set it
# it is NOT shared between instances, but specific to each
Instead you should increment the static variable:
def __init__(self, name):
self.name = name
MyClass.counter += 1 # this increments the static class variable
If you fix
#staticmethod
def count():
return MyClass.counter
this way, you can still call count() on instances as well as directly on the class.
t = MyClass("some")
print( MyClass.count() ) # fine
t1 = MyClass("other")
print( t.count() ) # only allowed if prefix the method with #staticmethod
Output:
1
2
See What is the difference between #staticmethod and #classmethod in Python? for further infos.

Python Class Objects Attribute Referencing

I have two classes. a and b.
In one of class a's methods, I created an object of class b. One of class b attributes takes a function. So say I gave it a random function but does this function of class b have access to class a's attribute? even though I didn't pass it in directly as a parameter?
class b:
def __init__(self):
self.attribute_function = None
class a:
def __init__(self):
self.temp = 10
self.counter = 0
def temp(self):
obj = b()
obj.attribute_function = lambda self: self.counter < self.temp
return obj.attribute_function()
if __name__ == "__main__":
#pass
obj = a()
print obj.temp()
In the above example, I tried to provide a really basic example, but if you run it, it doesn't work...
Revised Code, class a should look like this:
class a:
def __init__(self):
self.temp = 10
self.counter = 0
def temp(self):
obj = b()
obj.attribute_function = lambda args: self.counter < self.temp
return obj.attribute_function(1) # i added this 1 to fill in arg
This works:
class b:
def __init__(self):
self.attribute_function = None
class a:
def __init__(self):
self._temp = 10
self.counter = 0
def temp(self):
obj = b()
obj.attribute_function = lambda self=self: self.counter < self._temp
return obj.attribute_function()
if __name__ == "__main__":
obj = a()
print obj.temp()
On problem you had is self.temp = 10 which shadowed your method temp().
Another problem: lambda self: self.counter < self._temp. Your lambda function was expecting an argument. But omitting self is not a good idea lambda : self.counter < self._temp, because if you call obj.attribute_function() somewhere where self is not available or has changed - it will not find self or use another self. self=self fixes that.
But generally such magic is an anti-pattern. Tell us what are your trying to achieve, and there should be a better way to do what you want. Otherwise this kind of code will ensure many headaches.
I think this is a better solution (called strategy pattern):
class B:
def __init__(self, a):
self.a = a
def temp(self):
return self.a.temp()
class A:
def __init__(self):
self._temp = 10
self.counter = 0
def temp(self):
return self.counter < self._temp
if __name__ == "__main__":
obj = B(A())
print obj.temp()
Your example does not work because you have a name collision at temp
You have assigned temp to be both a method:
def temp(self):
and an attribute:
self.temp = 10

Problem with Python nested objects being stored in a dictionary

I'm having some trouble with changing the value of a class at runtime and then instantiating it into an object, then storing that object inside of another class and putting that into python dictionary.
Here is a small code snippet I wrote to illustrate the problem:
import unittest
class cls1(object):
def __init__(self, obj):
self.obj = obj
class cls2(object):
def __init__(self):
self.var = 1
class Testdict(unittest.TestCase):
def __init__(self):
self.objs = dict()
def runTest(self):
obj2 = cls2()
obj1 = cls1(cls2())
self.objs["test1"] = obj1
self.assertEqual(self.objs["test1"].obj.var, 1)
cls2.var = 2
self.assertEqual(cls2.var, 2)
obj1 = cls1(cls2())
self.objs["test2"] = obj1
self.assertEqual(self.objs["test1"].obj.var, 1)
self.assertEqual(self.objs["test2"].obj.var, 2)
if __name__ == "__main__":
d = Testdict()
d.runTest()
Why would cls2 not instantiate with having it's var equal to 2?
I hope this question makes some sense.
What you're showing can't work. Ever.
class Cls2(object):
def __init__(self):
self.var = 1
That's an instance variable. It's not a class variable. You can't access that .var with Cls2.var That variable only exists within each unique instance of the class.
Cls2.var = 2
Does not change the self.var instance variable. That creates a new class variable in the Cls2 class.
You'd need to do something like this.
class Cls2(object):
default= 1
def __init__(self):
self.var = Cls2.default
Now you can do
Cls2.default= 2
And the rest of whatever it is you're doing should work.
Your test would work if cls2 didn't overwrite cls.var when it is instantiated.
Try this:
class cls2(object):
def __init__(self):
try:
self.var
except:
self.var = 1
The try statement just checks to see if you've already set var.

Categories