Access class variables from another class - python

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)

Related

how to know from which class instance a function is called to access the instance attributes

I want to access an attribute of the class instance that called a function :
for example:
class A:
def a(self):
return B.q
class B:
q=0
def b(self):
M=A()
return M.a()
c=B()
c.q = 6
print(c.b())
the output will be 0 but I want it to print the q attribute of the instance c of the class B which has the value 6
Pass the instance as a parameter.
class A:
def a(self, b):
return b.q
class B:
q=0
def b(self):
M=A()
return M.a(self)
c=B()
c.q = 6
print(c.b())
This appears to be very bad program design. What are you trying to accomplish with this?
You have a class attribute and an instance attribute -- in that class -- of the same name, q. This makes your code difficult to follow and to maintain.
You have method B.b instantiate an instance of class A. You immediately call A.a, which has been assigned the questionable task of returning an instance attribute from and object of class B.
Clean up your design.
Use init appropriately for each class.
Design your class methods to work appropriately with the characteristics of instances of that class. Your question strongly suggests that your design is not yet clean in your mind, nor in code.
define an init method so that you can work with the instance attributes instead of the class variable
class A:
def a(self):
return B.q
class B:
def __init__(self):
self.q = 0
def b(self):
M=A()
return M.a()
c=B()
c.q = 6
print(c.b())

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'

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

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

Class method can not call other class methods within the same class

I have a class defined with two methods:
class A:
def called():
print 'called'
def caller(self):
called()
But caller can not use called directly
A().caller()
gives error
NameError: global name 'called' is not defined
How can I call the other unbounded method within the same class ?
Qualify the method with self or the class name A.
class A:
#staticmethod
def called():
print 'called'
def caller(self):
self.called()
# Or
A.called()
NOTE I changed the method called as a static method.

Python error in class

class exampleclass:
def meth01(self, name):
print self.name
obj1 = exampleclass()
obj1.meth01("James")
error message:
Traceback (most recent call last): File "<pyshell#5>", line 1, in
<module>
obj1.meth01("James") File "<pyshell#3>", line 3, in meth01
print self.name AttributeError: exampleclass instance has no attribute 'name'
So what have I done wrong to produce this error, the name is in the parameters And I tried to set what name was so that it could print?
You are printing self.name. This is a member variable of the class, not the input variable of the function meth01. In your function name refers to the input, and self.name refers to a member variable of the class. But you are not setting it.
Do this instead:
class ExampleClass:
def meth01(self, name):
print( name )
To understand what is going on, expand it like this:
class ExampleClass:
def setName(self, name):
self.name = name
def meth01(self, name):
print('Input variable name: ', name)
print('Member variable name: ', self.name)
ec = ExampleClass()
ec.meth01('John') # This line will fail because ec.name hasn't been set yet.
ec.setName('Jane')
ec.meth01('John')
# This will print:
#('Input variable name: ', 'John')
#('Member variable name: ', 'Jane')
You need to make your __init__ method
class exampleclass:
def __init__(self, name):
self.name = name
A variable name is part of the parameter list, but there's no name member value in the example class object itself (yet).
Think of what your code does, step by step. First it instantiates a new exampleclass object.
You then call obj1.meth01("James"). meth01 is passed with the values self = obj1 and name="James"
meth01 then tries to find a value stored as obj1.name, but none exists, since in this case name is local to the method meth01 and is not part of the object obj01 itself.
You need to make a constructor that is used to initialise an object.
Make your __init__ method like this.
class exampleclass:
def __init__(self, name):
self.name = name
NOTE: Declare the constructor as mentioned only.
You can understand self like this:
Self stores the address of the object from which the constructor or method is called.
So self.name=name would result in assigning the data member of the object from which it is called to the variable name which is passed as parameter to the constructor.

Categories