Calling a subclass variable in the parent class __init__()? [duplicate] - python

If I have the following code:
class Foo(object):
bar = 1
def bah(self):
print(bar)
f = Foo()
f.bah()
It complains
NameError: global name 'bar' is not defined
How can I access class/static variable bar within method bah?

Instead of bar use self.bar or Foo.bar. Assigning to Foo.bar will create a static variable, and assigning to self.bar will create an instance variable.

Define class method:
class Foo(object):
bar = 1
#classmethod
def bah(cls):
print cls.bar
Now if bah() has to be instance method (i.e. have access to self), you can still directly access the class variable.
class Foo(object):
bar = 1
def bah(self):
print self.bar

As with all good examples, you've simplified what you're actually trying to do. This is good, but it is worth noting that python has a lot of flexibility when it comes to class versus instance variables. The same can be said of methods. For a good list of possibilities, I recommend reading Michael Fötsch' new-style classes introduction, especially sections 2 through 6.
One thing that takes a lot of work to remember when getting started is that python is not java. More than just a cliche. In java, an entire class is compiled, making the namespace resolution real simple: any variables declared outside a method (anywhere) are instance (or, if static, class) variables and are implicitly accessible within methods.
With python, the grand rule of thumb is that there are three namespaces that are searched, in order, for variables:
The function/method
The current module
Builtins
{begin pedagogy}
There are limited exceptions to this. The main one that occurs to me is that, when a class definition is being loaded, the class definition is its own implicit namespace. But this lasts only as long as the module is being loaded, and is entirely bypassed when within a method. Thus:
>>> class A(object):
foo = 'foo'
bar = foo
>>> A.foo
'foo'
>>> A.bar
'foo'
but:
>>> class B(object):
foo = 'foo'
def get_foo():
return foo
bar = get_foo()
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
class B(object):
File "<pyshell#11>", line 5, in B
bar = get_foo()
File "<pyshell#11>", line 4, in get_foo
return foo
NameError: global name 'foo' is not defined
{end pedagogy}
In the end, the thing to remember is that you do have access to any of the variables you want to access, but probably not implicitly. If your goals are simple and straightforward, then going for Foo.bar or self.bar will probably be sufficient. If your example is getting more complicated, or you want to do fancy things like inheritance (you can inherit static/class methods!), or the idea of referring to the name of your class within the class itself seems wrong to you, check out the intro I linked.

class Foo(object):
bar = 1
def bah(self):
print Foo.bar
f = Foo()
f.bah()

bar is your static variable and you can access it using Foo.bar.
Basically, you need to qualify your static variable with Class name.

You can access class variables by object and directly by class name from the outside or inside of class and basically, you should access class variables directly by class name because if there are the same name class and instance variables, the same name instance variable is prioritized while the same name instance variable is ignored when accessed by object. So, using class name is safer than using object to access class variables.
For example, you can access the class variable by object and directly by class name from the outside of the class as shown below:
class Person:
name = "John" # Class variable
obj = Person()
print(obj.name) # By object
print(Person.name) # By class name
Output:
John
John
But, if you add the same name instance variable as the class variable by object:
class Person:
name = "John" # Class variable
obj = Person()
obj.name = "Tom" # Adds the same name instance variable as class variable
print(obj.name) # By object
print(Person.name) # By class name
Or, if you add the same name instance variable as the class variable by self in __init__():
class Person:
name = "John" # Class variable
def __init__(self, name):
self.name = name # Adds the same name instance variable as class variable
obj = Person("Tom")
print(obj.name) # By object
print(Person.name) # By class name
The same name instance variable is prioritized when accessed by object:
Tom # By object
John # By class name
And, you can also access the class variable by self and directly by class name from the inside of the instance method as shown below:
class Person:
name = "John" # Class variable
def test(self): # Instance method
print(self.name) # By "self"
print(Person.name) # By class name
obj = Person()
obj.test()
Output:
John
John
But, if you add the same name instance variable as the class variable by object:
class Person:
name = "John" # Class variable
def test(self): # Instance method
print(self.name) # By "self"
print(Person.name) # By class name
obj = Person()
obj.name = "Tom" # Adds the same name instance variable as the class variable
obj.test()
Or, if you add the same name instance variable as the class variable by self in __init__():
class Person:
name = "John" # Class variable
def __init__(self, name):
self.name = name # Adds the same name instance variable as the class variable
def test(self): # Instance method
print(self.name) # By "self"
print(Person.name) # Directly by class name
obj = Person("Tom")
obj.test()
The same name instance variable is prioritized when accessed by self:
Tom # By "self"
John # By class name

Related

Python Inner Class value assignment

I created a inner class within a class and created two instances of the class, but when assigning different values to the inner class properties, it is assigned to both instances. Can anyone help?
Here's the code
class cl1:
def __init__(self,tagName):
self.name = tagName
name1 = 'tagName'
class cl2:
name2 = 'name2'
test1 = cl1('test1')
test2 = cl1('test2')
test1.cl2.name2 = "cl1"
test2.cl2.name2 = 'cl2'
print (test1.cl2.name2)
When running it, the result is
cl2
Why it is not "cl1" as assigned?
The value:
test1.cl2.name2
Is a class attribute for the class cl2. It is associated with that class, not with instances of that class. So even though you're going through references to an instance of the cl1 class to set the value of that attribute, since there is only one of them, the last thing you set it to wins. Your print statements are printing that same single value.
Google "python class vs instance variables" for a number of good looking write-ups of what the differences are between class and instance variables/attributes.
Here's an example that 1) Provides instance vs class atributes just where it seems you wanted them, and 2) renames the classes involved to have uppercase names so it's obvious when you're referencing an instance attribute vs a class attribute.
class Cl1:
class Cl2:
def __init__(self, tagName):
self.name2 = tagName
def __init__(self, tagName1, tagName2):
self.name1 = tagName1
self.cl2 = Cl1.Cl2(tagName2)
test1 = Cl1('test1', 'test2')
test2 = Cl1('test2', 'test2')
test1.cl2.name2 = 'cl1'
test2.cl2.name2 = 'cl2'
print(test1.cl2.name2)
Result:
cl1
Note that because you want to have an instance of the inner class associated with each instance of the outer class, the inner class's constructor has to instantiate an instance of the inner class as part of creating the outer class instance.
Also note the references to self. Instance variables are created inside a classes's constructor (its __init__ function) by referencing them on self, a reference to the instance being created.

Python, how come we can create class variables that were not defined in class creation?

Let's say we have this simple Python code
class MyClass(object):
class_var = 1
def __init__(self, i_var):
self.i_var = i_var
Correct me if I get any of this wrong:
Class_Var is a class variable that is the same for all instances of MyClass object.
I_Var is an instance variable that only exists in instances of the MyClass object
foo = MyClass(2)
bar = MyClass(3)
foo.class_var, foo.i_var
## 1, 2
bar.class_var, bar.i_var
## 1, 3
Class variables are also properties of the class itself.
MyClass.class_var ##
## 1
MyClass.I_var should error out, correct?
Does that mean that class variables can be considered like instance variables of the class object itself (since all classes are objects) ?
MyClass.new_attribute = 'foo'
print(hasattr(ObjectCreator, 'new_attribute'))
That should return true. And
print (MyClass.new_attribute)
should return foo.
How come we can create a new class variable that was not defined in the original definition for that class?
Is
MyClass.new_attribute = 'foo'
the exact same thing as creating that class attribute in the original definition?
class MyClass(object):
class_var = 1
new_attribute = 'foo'
So we can create new class attributes at runtime? How does that not interfere with the init constructor that creates the class object and has those class variables as instance variables of the class object?
A class object is just an instance of yet another type, usually type (though you can change this using the metaclass parameter to the class statement).
Like most other instances, you can add arbitrary instance attributes to a class object at any time.
Class attributes and instance attributes are wholly separate; the former are stored on the class object, the latter on instances of the class.
There's nothing particularly special about __init__; it's just another method that, among other things, can attached new attributes to an object. What is special is that __init__ is called automatically when you create a new instance of the class by calling the class. foo = MyClass(2) is equivalent to
foo = MyClass.__new__(MyClass, 2)
foo.__init__(2)
The class statement
class MyClass(object):
class_var = 1
def __init__(self, i_var):
self.i_var = i_var
is roughly equivalent to
def my_class_init(self, i_var):
self.i_var = i_var
MyClass = type('MyClass', (object,), {'class_var': 1, '__init__: my_class_init})
The 3-argument form of type lets you pass a dict that creates class attributes when you first create the class, but you can always assign attributes after the fact as well:
MyClass = type('MyClass', (object,), {})
MyClass.class_var = 1
MyClass.__init__ = my_class_init
Just to blow your mind a little bit more, the call to type can be though of as
MyClass = type.__new__(type, 'MyClass', (object,), {...})
MyClass.__init__('MyClass', (object,), {...})
though unless you define a custom metaclass (by subclassing type), you never have to think about type itself having __new__ and __init__ methods.
Does that mean that class variables can be considered like instance variables of the class object itself (since all classes are objects) ?
Yes.
How come we can create a new class variable that was not defined in the original definition for that class?
Because Python is a dynamic language. A class can be created at run time - in fact, it is created at run time when you run Python interactively.
So we can create new class attributes at runtime?
Yes, unless the metaclass (the class of the class) has forbidden it.
How does that not interfere with the init constructor that creates the class object and has those class variables as instance variables of the class object?
The only rule is that you cannot use something that has not yet be defined or something that has been deleted:
>>> class MyClass(object):
class_var = 1
def __init__(self, i_var):
self.i_var = i_var
self.j_var = self.class_var + 1
>>> a = MyClass(2)
>>> del MyClass.class_var
>>> b = MyClass(3)
Traceback (most recent call last):
File "<pyshell#39>", line 1, in <module>
b = MyClass(3)
File "<pyshell#36>", line 6, in __init__
self.j_var = self.class_var + 1
AttributeError: 'MyClass' object has no attribute 'class_var'
There is no magic here: anything can only exists between its definition point and its destruction point. Python allows you to add attributes to objects at any time, except that some classes (for example object) forbid it.
With the previous a object of class MyClass, you could do:
a.z_var = 12
from that point, z_var will be an attribute of a but others objects of same class will not have it.
Simply object forbids that:
>>> o = object()
>>> o.x=1
Traceback (most recent call last):
File "<pyshell#41>", line 1, in <module>
o.x=1
AttributeError: 'object' object has no attribute 'x'

Access class variables from another class

I have a simple class A that gets the name from users.
class A:
def __init__(self, name = ''):
self.name = name
Then I want to create a class B that prints out this name. I tried:
class B:
def print_name(printing_name = A.name):
print(printing_name)
Then I call these methods:
m1 = A("x")
B.print_name(m1)
This returns the error
Traceback (most recent call last):
File "so.py", line 5, in <module>
class B:
File "so.py", line 7, in B
def print_name(printing_name = A.name):
AttributeError: class A has no attribute 'name'
I know that I did not assign a class variable in the class A, and thus the name attribute goes with specific instances, not the entire class. However, the name attribute has to connect with every specific instance because it changes from the case to case. Then how should I get this name in class B?
Change your class B to this:
class B:
#staticmethod
def print_name(obj):
print(obj.name)
The print_name method probably should be decorated as a "static method". The property "name" of self is an instance attribute which can not be referred directly from the class itself.
That's correct: name is an instance attribute, not a class attribute. IN this case, m1 has a name, but class A does not. You need to access the name of the input parameter, not attempt to print a class attribute.
You also need to make B.print_name a class function, since you're not calling it from an instance of B.
class B:
#staticmethod
def print_name(inst):
print(inst.name)
Output:
x
Edit: The answers suggesting #staticmethod are ideal if you understand what it does.
class A:
def __init__(self, name = ''):
self.name = name
class B:
def __init__(self):
pass
def print_name(self, var):
print (var.name)
Output:
>>> m1 = A("X")
>>> b = B()
>>> b.print_name(m1)
X
>>>
In this instance A is the name of the class, and you should not give it as the default argument for calling the print_name method. Have a look at keyword arguments for Python, and you will see that what you have written actually means that you have the default value set to the .name property of the class A, which does not exist unless the class is instantiated (i.e. an object is created of the class).
Your B class should read:
class B:
def print_name(printing_object):
print(printing_object.name)

Where to set the class members in Python? [duplicate]

Is there any difference at all between these classes besides the name?
class WithClass ():
def __init__(self):
self.value = "Bob"
def my_func(self):
print(self.value)
class WithoutClass ():
value = "Bob"
def my_func(self):
print(self.value)
Does it make any difference if I use or don't use the __init__ method for declaring the variable value?
My main worry is that I'll be using it one way, when that'll cause me further problems down the road.
Variable set outside __init__ belong to the class. They're shared by all instances.
Variables created inside __init__ (and all other method functions) and prefaced with self. belong to the object instance.
Without Self
Create some objects:
class foo(object):
x = 'original class'
c1, c2 = foo(), foo()
I can change the c1 instance, and it will not affect the c2 instance:
c1.x = 'changed instance'
c2.x
>>> 'original class'
But if I change the foo class, all instances of that class will be changed as well:
foo.x = 'changed class'
c2.x
>>> 'changed class'
Please note how Python scoping works here:
c1.x
>>> 'changed instance'
With Self
Changing the class does not affect the instances:
class foo(object):
def __init__(self):
self.x = 'original self'
c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'
I would like to add something to the responses that I read in this thread and this thread (which references this one).
Disclaimer: this remarks come from the experiments I ran
Variables outside __init__:
These are, in fact, static class variables and are, therefore, accesible to all instances of the class.
Variables inside __init__:
The value of these instance variables are only accesible to the instance at hand (through the self reference)
My contribution:
One thing that programmers must consider when using static class variables is that they can be shadowed by instance variables (if you are accessing the static class variables through the self reference).
Explanation:
Previously, I thought that both ways of declaring the variables were exactly the same (silly me), and that was partly because I could access both kind of variables through the self reference. It was now, when I ran into trouble, that I researched the topic and cleared it up.
The problem with accessing static class variables through the
self reference is that it only references the static class variable if there is no instance variable with the same name, and to make things worse, trying to redefine a static class variable through the self reference does not work because an instance variable is created which then shadows the previously-accesible static class variable.
To get around this problem, you should always reference static class variables through the name of the class.
Example:
#!/usr/bin/env python
class Foo:
static_var = 'every instance has access'
def __init__(self,name):
self.instance_var = 'I am %s' % name
def printAll(self):
print 'self.instance_var = %s' % self.instance_var
print 'self.static_var = %s' % self.static_var
print 'Foo.static_var = %s' % Foo.static_var
f1 = Foo('f1')
f1.printAll()
f1.static_var = 'Shadowing static_var'
f1.printAll()
f2 = Foo('f2')
f2.printAll()
Foo.static_var = 'modified class'
f1.printAll()
f2.printAll()
Output:
self.instance_var = I am f1
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = every instance has access
self.instance_var = I am f2
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = modified class
self.instance_var = I am f2
self.static_var = modified class
Foo.static_var = modified class
I hope this is helpful to someone
further to S.Lott's reply, class variables get passed to metaclass new method and can be accessed through the dictionary when a metaclass is defined. So, class variables can be accessed even before classes are created and instantiated.
for example:
class meta(type):
def __new__(cls,name,bases,dicto):
# two chars missing in original of next line ...
if dicto['class_var'] == 'A':
print 'There'
class proxyclass(object):
class_var = 'A'
__metaclass__ = meta
...
...
class User(object):
email = 'none'
firstname = 'none'
lastname = 'none'
def __init__(self, email=None, firstname=None, lastname=None):
self.email = email
self.firstname = firstname
self.lastname = lastname
#classmethod
def print_var(cls, obj):
print ("obj.email obj.firstname obj.lastname")
print(obj.email, obj.firstname, obj.lastname)
print("cls.email cls.firstname cls.lastname")
print(cls.email, cls.firstname, cls.lastname)
u1 = User(email='abc#xyz', firstname='first', lastname='last')
User.print_var(u1)
In the above code, the User class has 3 global variables, each with value 'none'. u1 is the object created by instantiating this class. The method print_var prints the value of class variables of class User and object variables of object u1. In the output shown below, each of the class variables User.email, User.firstname and User.lastname has value 'none', while the object variables u1.email, u1.firstname and u1.lastname have values 'abc#xyz', 'first' and 'last'.
obj.email obj.firstname obj.lastname
('abc#xyz', 'first', 'last')
cls.email cls.firstname cls.lastname
('none', 'none', 'none')
In Python, a class comes with member functions (methods), class variables, attributes/instance variables (and probably class methods too):
class Employee:
# Class Variable
company = "mycompany.com"
def __init__(self, first_name, last_name, position):
# Instance Variables
self._first_name = first_name
self._last_name = last_name
self._position = position
# Member function
def get_full_name(self):
return f"{self._first_name} {self._last_name}"
By creating an instance of the object
my_employee = Employee("John", "Wood", "Software Engineer")
we essentially trigger __init__ that is going to initialise the instance variables of the newly created Employee. This means that _first_name, _last_name and _position are explicit parameters of the specific my_employee instance.
Likewise, member functions return information or change the state of a specific instance.
Now any variable defined outside the constructor __init__ are considered to be class variables. Those variables are shared amongst all the instances of the class.
john = Employee("John", "Wood", "Software Engineer")
bob = Employee("Bob", "Smith", "DevOps Engineer0")
print(john.get_full_name())
print(bob.get_full_name())
print(john.company)
print(bob.company)
>>> John Wood
>>> Bob Smith
>>> mycompany.com
>>> mycompany.com
You can also use class methods in order to change the class variable for all the instances of the class. For example:
#classmethod
def change_my_companys_name(cls, name):
cls.company = name
and now change_my_companys_name()
bob.change_my_companys_name("mynewcompany.com")
will have effect on all the instances of class Employee:
print(bob.company)
print(john.company)
>>> mynewcompany.com
>>> mynewcompany.com
Example code:
class inside:
def __init__(self):
self.l = []
def insert(self, element):
self.l.append(element)
class outside:
l = [] # static variable - the same for all instances
def insert(self, element):
self.l.append(element)
def main():
x = inside()
x.insert(8)
print(x.l) # [8]
y = inside()
print(y.l) # []
# ----------------------------
x = outside()
x.insert(8)
print(x.l) # [8]
y = outside()
print(y.l) # [8] # here is the difference
if __name__ == '__main__':
main()
This is very easy to understand if you track class and instance dictionaries.
class C:
one = 42
def __init__(self,val):
self.two=val
ci=C(50)
print(ci.__dict__)
print(C.__dict__)
The result will be like this:
{'two': 50}
{'__module__': '__main__', 'one': 42, '__init__': <function C.__init__ at 0x00000213069BF6A8>, '__dict__': <attribute '__dict__' of 'C' objects>, '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None}
Note I set the full results in here but what is important that the instance ci dict will be just {'two': 50}, and class dictionary will have the 'one': 42 key value pair inside.
This is all you should know about that specific variables.
classes are like blueprints to create objects. Let's make a metaphor with building a house. You have the blueprint of the house so you can build a house. You can build as many houses as your resources allow.
In this metaphor, the blueprint is the class and the house is the instantiation of the class, creating an object.
The houses have common attributes like having a roof, living room, etc. This is where you init method goes. It constructs the object (house) with the attributes you want.
Lets suppose you have:
`class house:`
`roof = True`
`def __init__(self, color):`
`self.wallcolor = color`
>> create little goldlock's house:
>> goldlock = house() #() invoke's class house, not function
>> goldlock.roof
>> True
all house's have roofs, now let's define goldlock's wall color to white:
>> goldlock.wallcolor = 'white'
>>goldlock.wallcolor
>> 'white'
class foo(object):
mStatic = 12
def __init__(self):
self.x = "OBj"
Considering that foo has no access to x at all (FACT)
the conflict now is in accessing mStatic by an instance or directly by the class .
think of it in the terms of Python's memory management :
12 value is on the memory and the name mStatic (which accessible from the class)
points to it .
c1, c2 = foo(), foo()
this line makes two instances , which includes the name mStatic that points to the value 12 (till now) .
foo.mStatic = 99
this makes mStatic name pointing to a new place in the memory which has the value 99 inside it .
and because the (babies) c1 , c2 are still following (daddy) foo , they has the same name (c1.mStatic & c2.mStatic ) pointing to the same new value .
but once each baby decides to walk alone , things differs :
c1.mStatic ="c1 Control"
c2.mStatic ="c2 Control"
from now and later , each one in that family (c1,c2,foo) has its mStatica pointing to different value .
[Please, try use id() function for all of(c1,c2,foo) in different sates that we talked about , i think it will make things better ]
and this is how our real life goes . sons inherit some beliefs from their father and these beliefs still identical to father's ones until sons decide to change it .
HOPE IT WILL HELP
As noted by S.Lott,
Variable set outside init belong to the class. They're shared by
all instances.
Variables created inside init (and all other method functions) and
prefaced with self. belong to the object instance.
However,
Note that class variables can be accessed via self.<var> until they are masked by an object variable with a similar name This means that reading self.<var> before assigning it a value will return the value of Class.<var> but afterwards it will return obj.<var> . Here is an example
In [20]: class MyClass:
...: elem = 123
...:
...: def update(self,i):
...: self.elem=i
...: def print(self):
...: print (MyClass.elem, self.elem)
...:
...: c1 = MyClass()
...: c2 = MyClass()
...: c1.print()
...: c2.print()
123 123
123 123
In [21]: c1.update(1)
...: c2.update(42)
...: c1.print()
...: c2.print()
123 1
123 42
In [22]: MyClass.elem=22
...: c1.print()
...: c2.print()
22 1
22 42
Second note: Consider slots. They may offer a better way to implement object variables.
Try this and check the difference
class test:
f = 3
def __init__(s, f):
s.__class__.f = f
s.f = s.__class__.f
print(f'def __init__(s, {f})')
print(f's.__class__.f = {f}')
print(f's.f={s.__class__.f}')
print(f'f={f}')
print('===============init over===========')
def setinstancetoOne(s, f):
print(f'def setinstancetoOne(s, {f})')
s.f = f
print(f'class var f = {f}')
def useClassname(test):
print(f'>>>>def useClassname({test})')
print(f'test.f {test.f}')
def p_method(s):
print(f'>>>>def p_method({s})')
print(f's.f {s.f}')
print(f'test.f {test.f}')
print(f's.__class__.f {s.__class__.f}')
print(f'class var f={f}')
# test.__init__.f = 19
t = test(2)
t.useClassname()
t.p_method()
print(f'Outside class t.f {t.f}')
print(f'Outside class test.f {test.f}')
print('______difference__________')
t = test(2)
t.setinstancetoOne(1)
t.useClass()
t.p_method()
print(f'Outside class instance variable(2) {t.f}')
print(f'Outside class class variable(3) {test.f}')

Does a metaclass instantiate the class's attributes first?

From this answer to "what is a metaclass?" I got this:
You write class Foo(object) first, but the class object Foo is not created in memory yet.
Python will look for metaclass in the class definition. If it finds it, it will use it to create the object class Foo. If it doesn't, it will use type to create the class.
Having tested it, it seems that the attributes of the class are instantiated before the constructor of the class is run. What am I misunderstanding?
Test code:
class meta(type):
def __init__(cls, name, bases, dic):
type.__init__(cls, name, bases, dic)
print hasattr(cls, "a")
cls.a = "1"
class A(object):
a = "a"
__metaclass__ = meta
class B(object):
__metaclass__ = meta
class C(object):
__metaclass__ = meta
a = "a"
print A.a
print B.a
print C.a
Output:
True
False
True
1
1
1
The class body is run before the class is constructed, yes.
The body of the class provides a temporary namespace, and all local names in that namespace are given as a dictionary to construct the class object, together with the base classes and a name for the class.
You can do this with the type() constructor too:
>>> Foo = type('Foo', (), {'a': 1})
>>> Foo.a
1
The class body is basically executed as a function, with the local namespace of that function being used to create the class attributes, the 3rd argument to type() above.
In python 3 you have a little more influence on that process with the __prepare__ hook on a metaclass. __prepare__ should be a class method that returns a initial namespace for the class body; use it to inject extra names into the generated class body before the class body is executed:
class MyMeta(type):
#classmethod
def __prepare__(mcl, name, bases):
return {'a': 1}

Categories