Python... Static variables? [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Instance variables vs. class variables in Python
What is the difference between these two situations and how is it treated with in Python?
Ex1
class MyClass:
anArray = {}
Ex2
class MyClass:
__init__(self):
self.anArray = {}
It seems like the in the first example the array is being treated like a static variable. How does Python treat this and what is the reason for this?

In the first example, anArray (which in Python is called a dictionary, not an array) is a class attribute. It can be accessed using MyClass.anArray. It exists as soon as the class is defined.
In the second example, anArray is an instance attribute. It can be accessed using MyClass().anArray. (But note that doing that just throws away the MyClass instance created; a more sensible example is mc = MyClass(); mc.anArray['a'] = 5.) It doesn't exist until an instance of the class is created.

It is declared diffrent area.
Ex1 is Like global or static variable.
obj = MyClass()
obj2 = MyClass()
print "IS one instance ", id(obj.anArray) == id(obj2.anArray)
Ex2 is local attribute.
obj = MyClass()
obj2 = MyClass()
print "IS one instance ", id(obj.anArray) == id(obj2.anArray)

Related

How to call a function within an attribute? [duplicate]

This question already has answers here:
How to access (get or set) object attribute given string corresponding to name of that attribute
(3 answers)
Closed 3 years ago.
I have a Python class that have attributes named: date1, date2, date3, etc.
During runtime, I have a variable i, which is an integer.
What I want to do is to access the appropriate date attribute in run time based on the value of i.
For example,
if i == 1, I want to access myobject.date1
if i == 2, I want to access myobject.date2
And I want to do something similar for class instead of attribute.
For example, I have a bunch of classes: MyClass1, MyClass2, MyClass3, etc. And I have a variable k.
if k == 1, I want to instantiate a new instance of MyClass1
if k == 2, I want to instantiate a new instance of MyClass2
How can i do that?
EDIT
I'm hoping to avoid using a giant if-then-else statement to select the appropriate attribute/class.
Is there a way in Python to compose the class name on the fly using the value of a variable?
You can use getattr() to access a property when you don't know its name until runtime:
obj = myobject()
i = 7
date7 = getattr(obj, 'date%d' % i) # same as obj.date7
If you keep your numbered classes in a module called foo, you can use getattr() again to access them by number.
foo.py:
class Class1: pass
class Class2: pass
[ etc ]
bar.py:
import foo
i = 3
someClass = getattr(foo, "Class%d" % i) # Same as someClass = foo.Class3
obj = someClass() # someClass is a pointer to foo.Class3
# short version:
obj = getattr(foo, "Class%d" % i)()
Having said all that, you really should avoid this sort of thing because you will never be able to find out where these numbered properties and classes are being used except by reading through your entire codebase. You are better off putting everything in a dictionary.
For the first case, you should be able to do:
getattr(myobject, 'date%s' % i)
For the second case, you can do:
myobject = locals()['MyClass%s' % k]()
However, the fact that you need to do this in the first place can be a sign that you're approaching the problem in a very non-Pythonic way.
OK, well... It seems like this needs a bit of work. Firstly, for your date* things, they should be perhaps stored as a dict of attributes. eg, myobj.dates[1], so on.
For the classes, it sounds like you want polymorphism. All of your MyClass* classes should have a common ancestor. The ancestor's __new__ method should figure out which of its children to instantiate.
One way for the parent to know what to make is to keep a dict of the children. There are ways that the parent class doesn't need to enumerate its children by searching for all of its subclasses but it's a bit more complex to implement. See here for more info on how you might take that approach. Read the comments especially, they expand on it.
class Parent(object):
_children = {
1: MyClass1,
2: MyClass2,
}
def __new__(k):
return object.__new__(Parent._children[k])
class MyClass1(Parent):
def __init__(self):
self.foo = 1
class MyClass2(Parent):
def __init__(self):
self.foo = 2
bar = Parent(1)
print bar.foo # 1
baz = Parent(2)
print bar.foo # 2
Thirdly, you really should rethink your variable naming. Don't use numbers to enumerate your variables, instead give them meaningful names. i and k are bad to use as they are by convention reserved for loop indexes.
A sample of your existing code would be very helpful in improving it.
to get a list of all the attributes, try:
dir(<class instance>)
I agree with Daenyth, but if you're feeling sassy you can use the dict method that comes with all classes:
>>> class nullclass(object):
def nullmethod():
pass
>>> nullclass.__dict__.keys()
['__dict__', '__module__', '__weakref__', 'nullmethod', '__doc__']
>>> nullclass.__dict__["nullmethod"]
<function nullmethod at 0x013366A8>

Python 3.5 handling lists strangely [duplicate]

This question already has answers here:
python class instance variables and class variables
(4 answers)
Closed 5 years ago.
I came across some rather strange behavior.
class Example:
test = []
def __init__(self):
print(self.test)
self.test.append(0)
ex1 = Example()
ex2 = Example()
ex3 = Example()
I'd expect this to output [] every time, however, I get:
[]
[0]
[0, 0]
What is this wizardry? Could you help me understand?
Thank, you!
Edit:
Hey, thank you for the quick answers.
Just to clarify, if "test" is static then why do I not notice this behavior when I replace "self.test.append(0)" with "self.test = [0]"?
test is a static class attribute, which you are continually updating with values. Python is different from some other languages in this way. To make it an object attribute, use self.test = [] in your constructor.
test there is a class-level static variable, which is shared between the instances of the class.
You'll want to initialize test within the __init__ method.
class Example:
def __init__(self):
self.test = []
print(self.test)
self.test.append(0)

Making a variable cross module in Python - Within a class and function

I'm trying to use a variable in other python modules, like this:
In a.py:
class Names:
def userNames(self):
self.name = 'Richard'
In z.py:
import a
d = a.Names.name
print d
However this doesn't recognise the variable name and the following error is received:
AttributeError: type object 'Names' has no attribute 'name'
Thanks
There are lots of different scopes a variable can be bound to, which is what you seem to be confused about. Here are a few:
# a.py
a = 1 # (1) is module scope
class A:
a = 2 # (2) is class scope
def __init__(self, a=3): # (3) is function scope
self.a = a # (4) self.a is object scope
def same_as_class(self):
return self.a == A.a # compare object- and class-scope variables
def same_as_module(self):
return self.a == a # compare object- and module-scope variables
Now see how these different variables (I only called them all a to make the point, please don't do this for real) are named, and how they all have different values:
>>> import a
>>> a.a
1 # module scope (1)
>>> a.A.a
2 # class scope (2)
>>> obj1 = a.A() # note the argument defaults to 3 (3)
>>> obj1.a # and this value is bound to the object-scope variable (4)
3
>>> obj.same_as_class()
False # compare the object and class values (3 != 2)
>>> obj2 = a.A(2) # now create a new object, giving an explicit value for (3)
>>> obj2.same_as_class()
True
Note we can also change any of these values:
>>> obj1.same_as_module()
False
>>> obj1.a = 1
>>> obj1.same_as_module()
True
For reference, your z.py above should probably look like:
import a
n = a.Names()
d.userNames()
d = n.name
print d
because a.Name is a class, but you're trying to refer to an object-scope variable. An object is an instance of a class: I've called my instance n. Now I have an object, I can get at the object-scope variable. This is equivalent to Goranek's answer.
In terms of my previous example, you were trying to access obj1.a without having an obj1 or anything like it. I'm not really sure how to make this clearer, without turning this into an introductory essay on OO and Python's type system.
"I've checked again and it's because I'm importing from is a Tornado Framework and the variable is within a class."
Accordingly, your problem is not the one shown in your question.
If you actually want to access the variable of a class (and likely, you don't), then do this:
from othermodule import ClassName
print ClassName.var_i_want
You probably want to access the variable as held inside an instance:
from othermodule import ClassName, some_func
classnameinstance = some_func(blah)
print classnameinstance.var_i_want
Update Now that you have completely changed your question, here is the answer to your new question:
IN this code:
class Names:
def userNames(self):
name = 'Richard'
name is not a variable accessible outside of the activation of the method userNames. This is known as a local variable. You would create an instance variable by changing the code to:
def userNames(self):
self.name = 'Richard'
Then, if you have an instance in a variable called classnameinstance you can do:
print classnameinstance.name
This will only work if the variable has been already created on the instance, as by calling userNames.
You don't need to import the class itself if there is some other way to receive instances of the class.
file:a.py
class Names:
def userNames(self):
self.name = 'Richard'
file:z.py
import a
c = a.Names()
c.userNames()
what_you_want_is = c.name
Btw, this code makes no sense..but this is apparently what you want
Better a.py
class Names:
def userNames(self, name):
self.name = name
Better z.py
import a
c = a.Names()
c.userNames("Stephen or something")
what_you_want_is = c.name
# what_you_want_is is "Stephen or something"

confusing about python class and instance variables

I saw the following Python documentation which says that "define variables in a Class" will be class variables:
"Programmer's note: Variables defined in the class definition are
class variables; they are shared by all instances. "
but as I wrote sample code like this:
class CustomizedMethods(object):
class_var1 = 'foo'
class_var2 = 'bar'
cm1 = CustomizedMethods()
cm2 = CustomizedMethods()
print cm1.class_var1, cm1.class_var2 #'foo bar'
print cm2.class_var1, cm2.class_var2 #'foo bar'
cm2.class_var1, cm2.class_var2 = 'bar','for'
print cm1.class_var1, cm1.class_var2 #'foo bar' #here not changed as my expectation
print cm2.class_var1, cm2.class_var2 #'bar foo' #here has changed but they seemed to become instance variables.
I'm confused since what I tried is different from Python's official documentation.
When you assign an attribute on the instance, it is assigned on the instance, even if it previously existed on the class. At first, class_var1 and class_var2 are indeed class attributes. But when you do cm1.class_var1 = "bar", you are not changing this class attribute. Rather, you are creating a new attribute, also called class_var1, but this one is an instance attribute on the instance cm1.
Here is another example showing the difference, although it still may be a bit tough to grasp:
>>> class A(object):
... var = []
>>> a = A()
>>> a.var is A.var
True
>>> a.var = []
>>> a.var is A.var
False
At first, a.var is A.var is true (i.e., they are the same object): since a doesn't have it's own attribute called var, trying to access that goes through to the class. After you give a its own instance attribute, it is no longer the same as the one on the class.
You're assigning attributes on the instances, so yes, they become instance variables at that point. Python looks for attributes on whatever object you specify, then if it can't find them there, looks up the inheritance chain (to the class, the class's parents, etc.). So the attribute you assign on the instance "shadows" or "hides" the class's attribute of the same name.
Strings are immutable, so the difference between a class and instance variable isn't as noticable. For immutable variables in a class definition, the main thing to notice is less use of memory (i.e., if you have 1,000 instances of CustomizedMethods, there's still only one instance of the string "foo" stored in memory.)
However, using mutable variables in a class can introduce subtle bugs if you don't know what you're doing.
Consider:
class CustomizedMethods(object):
class_var = {}
cm1 = CustomizedMethods()
cm2 = CustomizedMethods()
cm1.class_var['test'] = 'foo'
print cm2.class_var
'foo'
cm2.class_var['test'] = 'bar'
print cm1.class_var
'bar'
When you reassigned the cm2 variables, you created new instance variables that "hid" the class variables.
>>> CustomizedMethods.class_var1 = 'one'
>>> CustomizedMethods.class_var2 = 'two'
>>> print cm1.class_var1, cm1.class_var2
one two
>>> print cm2.class_var1, cm2.class_var2
bar for
Try to
print cm1.__dict__
print cm2.__dict__
it will be enlightning...
When you ask cm2 for an attribute it first looks among the attributes of the instance (if one matches the name) and then if there is no matching attribute among the class attributes.
So class_var1 and class_var2 are the names of the class attributes.
Try also the following:
cm2.__class__.class_var1 = "bar_foo"
print cm1.class_var1
what do you expect?

List in a Python class shares the same object over 2 different instances? [duplicate]

This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 15 days ago.
I created a class:
class A:
aList = []
now I have function that instantiate this class and add items into the aList.
note: there are 2 items
for item in items:
a = A();
a.aList.append(item);
I find that the first A and the second A object has the same number of items in their aList.
I would expect that the first A object will have the first item in its list and the second A object will have the second item in its aList.
Can anyone explain how this happens ?
PS:
I manage to solve this problem by moving the aList inside a constructor :
def __init__(self):
self.aList = [];
but I am still curious about this behavior
You have defined the list as a class attribute.
Class attributes are shared by all instances of your class.
When you define the list in __init__ as self.aList, then the list is an attribute of your instance (self) and then everything works as you expected.
You are confusing class and object variables.
If you want objects:
class A(object):
def __init__(self):
self.aList = []
in your example aList is a class variable, you can compare it with using the 'static' keyword in other languages. The class variable of course is shared over all instances.
This happened because list is a mutable object, and it is created once only when defining the class, that is why it becomes shared when you create two instances. Eg,
class A:
a = 0 #immutable
b = [0] #mutable
a = A()
a.a = 1
a.b[0] = 1
b = A()
print b.a #print 0
print b.b[0] #print 1, affected by object "a"
Therefore, to solve the problem, we can use constructor like what you have mentioned. When we put the list in constructor, whenever the object is instantiated, the new list will also be created.
In Python, variables declared inside the class definition, instead of inside a method, are class or static variables. You may be interested in taking a look at this answer to another question.

Categories

Resources