In python class (say class C) lets say we have class variable V = 0. Lets say this is a counter that keeps track of how many objects of the class have been created.
In the init methid, say we want to fetch the class variable value. We can do this either by writing C.V or self.V - assuming both do exactly the same thing.
To set the value of this class variable, there are same 2 options so what is the difference of using:
C.V += 1 versus self.V += 1
Is it that using self will update the variable at that object level and other objects wont get the change? Or do both approach behave the same.
Setting C.V refers to the class's definition. This will set the value for all objects of the same class. Using self refers to the current instance, or object, of that class. This will not affect other objects of the same class.
EDIT -- Credits to #Jdw136
And adding on to what #CalderWhite said, when you use a normal variable in a class (C.V), that variable is shared among all instances of that class. On the other hand when you use the self. Method (self.V), each instance of that object gets its own variable all to itself. Keeping this in mind, you can use this knowledge to avoid creating the same variable in the stack over and over.
Related
Is the class (method?) just to customize a new type?
Is an instance just a particular variable of a new customized type?
Really confused about "attribute" because there are many different opinions like here and here.
class PartyAnimal:
x = 0
def party(self) :
self.x = self.x + 1
print("So far",self.x)
an = PartyAnimal()
btw how's the self.x = self.x + 1 work here?
I appreciate your help and pardon me for the broken English.
Is the class (method?) just to customize a new type?
A class is the framework for an object. An object is an instance of the class:
class PartyAnimal:
...
# `an` is an instance of PartyAnimal
an = PartyAnimal()
A method is a function within the class. In your example, def party(self) is a method of PartyAnimal
Really confused about "attribute"
An attribute of a class is the class.something thing.
The attribute of your PartyAnimal class is the self.x part, where x is an attribute of PartyAnimal. You can get the value of x for each instance with:
class PartyAnimal:
x = 0
def party(self) :
self.x = self.x + 1
print("So far",self.x)
>>> an = PartyAnimal()
>>> an.x
0
# Then run the method
>>> an.party()
'So far 1'
>>> an.x
1
Docs - https://docs.python.org/3/glossary.html#term-attribute
btw how's the self.x = self.x + 1 work here?
You're adding 1 to the attribute x. Same as x += 1 if you weren't using classes
I recommend reading the w3 article on classes. It's really good
Putting in very easy words, any variables that are defined inside a class are called attributes. An instance of a class is a copy of that particular class.
When you instantiate a class PartyAnimal(), a copy of it is created. You assign it to a variable of the same type an.
an = PartyAnimal()
Now, let's refer to an as an instance of the class PartyAnimal(). an contains an attribute x which is initially set to the value 0. It can be accessed using the . operator.
print(an.x) # output: 0
By default, attributes of a class in python are public. Meaning they can be accessed outside of the class. If you want to increment the value of x by 1, you can do it by:
an.x = an.x + 1
print(an.x) # output: 1
Now, talking about the method party(), which takes the parameter self. self represents the instance of the class. In party(), the value of x is incremented. To know that we are referring to the variable x of that instance and not any other x (sometimes the variable with the name x is passed into the function), we use self.
Refer to this to know more about self.
The first link you posted explains most of your questions...
Explaining what methods are - they're functions inside the object and class:
An object can contain a number of functions (which we call methods)
The second link you posted confirms this:
Method: A function which is defined inside a class body. If called as an attribute of an instance of that class, the method will get the instance object as its first argument (which is usually called self). See function and nested scope.
Explaining what classes are...
the class keyword defines a template indicating what data and code will be contained in each object of type PartyAnimal. The class is like a cookie cutter and the objects created using the class are the cookies.
counts = dict()
Here we instruct Python to construct an object using the dict template (already present in Python), return the instance of dictionary, and assign it to the variable counts.
It compares dict and PartyAnimal as both templates, both types of objects.
Explaining what attributes are - they're data inside the object and class:
We call data items that are part of the object attributes.
Attribute: A value associated with an object which is referenced by name using dotted expressions.
Explaining that object and instance are interchangeable and that they are assigned to variables...
an = PartyAnimal() This is where we instruct Python to construct (i.e., create) an object or instance of the class PartyAnimal.
Python constructs the object with the right data and methods and returns the object which is then assigned to the variable an.
When the PartyAnimal class is used to construct an object, the variable an is used to point to that object.
Explaining your question about self.x = self.x+1...
When the party method is called, the first parameter (which we call by convention self) points to the particular instance of the PartyAnimal object that party is called from. Within the party method, we see the line:
self.x = self.x + 1
This syntax using the dot operator is saying "the x within self". Each time party() is called, the internal x value is incremented by 1 and the value is printed out.
I could not find conflicting information between the two links you posted.
Suppose the following class hierarchy in Python:
class O:
variable = 0
class A(O):
variable = "abcdef"
class B(O):
variable = 1.0
class X(A, B):
pass
x = X()
When an instance of X gets created, does Python allocate the memory for each variable in the base classes, or only for the resolved variable?
It doesn't allocate any variables when you create an instance of X; all of your variables are class attributes, not instance attributes, so they're attached to their respective classes, not to the instance. X and instances of X would see variable with the value from A thanks to the order in which it checks base classes for names when the name isn't set on the instance, but all three versions of variable would exist.
If you did make them instance attributes (assigned to self.variable in __init__ for each class), and used super() appropriately to ensure all __init__s called, there'd only be one copy of self.variable when you were done initializing (which one survived would depend on whether you initialized self.variable or called super().__init__() first in the various __init__ implementations). This is because Python doesn't "resolve" names in the way you're thinking; instance attributes are stored by string name on a dict under-the-hood, and the last value assigned to that name wins.
The only way to have multiple instance attributes with the "same" name is to make them private, by prefixing them with __; in that case, with all three defining self.__variable, there'd be a uniquely name-mangled version of __variable seen by the methods of each class (and not used by parent or child classes); X wouldn't see one at all, but methods it inherited from A would see A's version, methods inherited from B would see B's version, etc.
class Channel(object)
channel_mapping = {
'a': 001,
'b': 002,
'c': 003
}
def __init__(self):
...
def process(self, input):
channels = input.split(',')
for channel in channels:
if channel in self.channel_mapping:
channel = self.channel_mapping[channel]
break
...
I defined channel_mapping as class variable, and why do I need to use self to refer to it? I thought I should just use channel_mapping or cls.channel_mapping in the process() function.
Also, to define channel_mapping as a class variable like this, or define it as an instance variable in the initializer, is there any thread safety concern in either case?
I defined 'channel_mapping' as class variable, and why do I need to
use 'self' to refer to it?
You can refer class variable via self (if you ensure it's read-only) and cls inside the class and it's methods and via classes object or instances from outside of the class.
What is the difference between using cls and self? cls is being used in classmethods since they doesn't require initialization and so instance of the object, and self is used inside the methods which do require instances of the object.
I thought I should just use
'channel_mapping'
Scopes inside python doesn't work as in C# for example, where you can call class variable by just writing it's name omitting this where it's redundant. In Python you have to use self to refer to the instance's variable. Same goes to the class variables but with cls (or self) instead.
If you are referencing channel_mapping you are just referencing a variable from the current or a global scopes whether it exists or not and not from the class or it's instance.
or cls.channel_mapping in the 'process' function?
From the class methods you would want for sure to use cls.channel_mapping since cls represents class object. But from the instance's methods, where instead of cls you have self you can refer to the class variable using self.__class__.channel_mapping. What it does is simply returning instance's class which is equal to cls, and calls class variable channel_mapping afterwards.
self.channel_mapping though would return the same result but just because in your code there are no instance attribute called channel_mapping and so python can resolve your reference to the class variable. But if there would be channel_mapping variable inside the instance it won't be any longer related to the original class variables, so in that case you would want to keep channel_mapping read-only.
Summarise, to refer class variable from the class method you would want to just use a cls and to refer class variable from the instance method you better use self.__class__.var construction instead of self.var one.
Also, to define 'channel_mapping' as a class variable like this, or define it as an instance variable in the initializer, is there any thread safety concern in either case?
There are situations when you want to change variables in all instances simultaneously, and that's when class variables comes in handy, you won't need to update every responsible instance variable in every instance, you will just update class variable and that's it.
But speaking of thread safety I'm not really sure will it be simultaneously updated in every thread or not, but self.__class__ will return updated version of a class a soon as it will be updated, so self.__class__ variables will be up to date every time you call it minimizing period within which different threads will use different values of the same variable.
Going up with the initialized variable though, will take longer to update if there are more than one instance so i would consider it less threadsafe.
What's the lifetime of a class attribute, in Python? If no instances of the class are currently live, might the class and its class attributes be garbage-collected, and then created anew when the class is next used?
For example, consider something like:
class C(object):
l = []
def append(self, x):
l.append(x)
Suppose I create an instance of C, append 5 to C.l, and then that instance of C is no longer referenced and can be garbage-collected. Later, I create another instance of C and read the value of C.l. Am I guaranteed C.l will hold [5]? Or is it possible that the class itself and its class attributes might get garbage-collected, and then C.l = [] executed a second time later?
Or, to put it another way: Is the lifetime of a class attribute "forever"? Does a class attribute have the same lifetime as a global variable?
You asked several questions.
What's the lifetime of a class attribute, in Python?
A class attribute lives as long as there is a reference to it. Since the class holds a reference, it will live as at least long as the class lives, assuming that the class continues to hold the reference. Additionally, since each object holds a reference, it will live at least as long as all of the objects, assuming that each object continues to hold the reference.
Am I guaranteed C.l will hold [5]?
In the hypothetical that you describe, yes.
Or is it possible that the class itself and its class attributes might get garbage-collected, and then C.l = [] executed a second time later?
Not given your hypothetical that you are able to construct an instance of C. If you are able to construct a second instance of C, then C must exist, and so too must C.l
Is the lifetime of a class attribute "forever"?
No. The lifetime of a class attribute follows the lifetime rules of any object. It exists as long a reference to it exists. In the case of C.l, a reference exists in the class, and a reference exists in each instance. If you destroy all of those, then C.l will also be destroyed.
Does a class attribute have the same lifetime as a global variable?
Sort of: a class attribute exists until the last reference goes away. A global variable also exists until the last reference goes away. Neither of these are guaranteed to last the entire duration of the program.
Also, a class defined at module scope is a global variable. So the class (and, by implication, the attribute) have the same lifetime as a global variable in that case.
If no instances of the class are currently live, might the class and its class attributes be garbage-collected, and then created anew when the class is next used?
No. There is no "next use" of a class that's been garbage-collected, because the only way it can be garbage-collected is if there's no way left to use it.
Suppose I create an instance of C, append 5 to C.l, and then that instance of C is no longer referenced and can be garbage-collected. Later, I create another instance of C and read the value of C.l. Am I guaranteed C.l will hold [5]?
Yes. The class has a live reference because you created another instance, and the list has a live reference as an attribute on the class.
Does a class attribute have the same lifetime as a global variable?
If the class holds a reference to something, that something will live at least as long as the class.
So I have a somewhat long and growing list of classes in a script. At a certain point in the script I want to be able to test an arbitrary instance for its type, and then whatever that type is, I want to create a second object of the same type. I've tried researching this and I know I can accomplish this by storing every class in a dictionary, like so:
class Foo(object):
pass
class Bar(object):
pass
d = {"Foo": Foo, "Bar": Bar}
x = dict["Foo"]()
It does the trick, allowing me to use a variable or string containing the name of the class, in order to create an instance of the class. However, it requires that every time I create a new class I have to remember to also put a new entry in the dictionary--which isn't the worst thing in the world, but as they say, if you're doing the same task more than once you should make a computer do it.
Is there a better way? Can you somehow take a variable or string containing the name of a class, and without knowing what value the variable or string has, generate an instance of the class?
So this is answering your problem rather than your question, but it seems you actually want to create another instance of an object rather than find a class by name. So that is even easier because you can find the class of an object with the type function. So to create a new instance b of the same type as a but with constructor parameters args simply do:
b = type(a)(args)
All classes are in globals dictionary (dictionary containing the current scope's global variables). Get the dictionary with globals(), and then find it by name (string). As a result you will get a class, which can be instantiated with ().
class Foo(object):
pass
x = globals()['Foo']()
Not sure why Huazuo Gao didn't make that an answer, but it solves my problem exactly and I've never seen that solution in my research on this problem--so I'll go ahead and punch it up as an answer.
You can do it using the string of the name of the class and the eval() function. So
class Foo(object):
pass
a = Foo()
s = str(type(a))
# The string produced isn't quite the name of the class so it has to be stripped
# of some surrounding characters.
m = s.find('.')
n1 = s.find("'")
n2 = s[n1+1:].find("'")
s = s[m+1:n1+n2+1]
b = eval(s + "()")
produces the desired behavior.