According to my understanding, the first argument passed in a class method is the class itself where that class method is defined. So for example, consider the following code:
class A(object):
__x=10
#classmethod
def clam(cls,*args):
print(cls.__x)
class B(A):
__x=50
And when i called :
B.clam()
the output was 10 which is OK as per my understanding because the class method being called is defined in class A, so class A will be passed implicitly to clam() and the value of __x there is 10.
But when i ran the following code:
class A(object):
x=10
#classmethod
def clam(cls,*args):
print(cls.x)
class B(A):
x=50
and when i called:
B.clam()
My life was suddenly ruined. The output is 50.
The only difference between both the cases is that x was private in former one.
What happened exactly? Why the output from the later one is 50 ? Was there any scope change or suddenly the first parameter passed to class method defined in A became class B ?
The first parameter in the class method is the class on which you are calling the method, not (necessarily) the class that defines the method. (Having a variable that always holds the same class would probably not be that useful.)
In the first case, name mangling distinguishes the two fields, to protect you from accidentally shadowing private variables in a subclass. The field A.__x becomes A._A__x and B.__x becomes B._B__x. This ensures that you can't accidentally pick up a field in a subclass with a similar name to your private field in A. That's part of the reason name mangling exists.
In the second case, there is no name mangling: you get the x field as defined in B, the class you are calling the method on.
Related
Supposed that you have a python class (say B) that is a derived class of some other class (say A) and that class A has both class variables and #classmethods that help you change or view these class variables. I had assumed that a #classmethod in class A that sets a class A class variable using the syntax cls.variable_name = value would work.
This seems to work sometimes but not always which confuses me. Below is an example that does not set the class variables as I would expect. Therefore I cannot tell what cls.something will be accessing and so I have to use A.something which seems that I will be missing the capabilities of cls.something in #classmethods. What does cls.something actually access in class methods and why does the following example not set the test class class variables?
The following example with output hopefully demonstrates what I mean:
class Test():
epf = 'A'
#classmethod
def set_formats(cls, p):
cls.epf = p
#classmethod
def form(cls):
return cls.epf
class Mytest(Test):
pass
Here is the output:
>>>c=Mytest
>>>Test.form()
'A'
>>>c.set_formats(p='a')
>>>Test.epf
'A'
>>>c.form()
'a'
>>>c.epf
'a'
So in this example the classmethods are not changing the class variable as I would expect and instead an instance variable seems to appear. If I do the above without a derived class then it works as expected. Hmm? Clearly missing something here!
Now if I change the c.set_formats(p='a', f='A') to Test.set_formats(p='a', f='A') it does work. Is it because c.set_formats uses the class method with cls being an instance?
Edit: Made the code much smaller and changed conventions as requested.
Is it because c.set_formats uses the class method with cls being an instance?
Yes, you can check via print calls showing the ids of the involved objects.
I have a class with a private constant _BAR = object().
In a child class, outside of a method (no access to self), I want to refer to _BAR.
Here is a contrived example:
class Foo:
_BAR = object()
def __init__(self, bar: object = _BAR):
...
class DFoo(Foo):
"""Child class where I want to access private class variable from parent."""
def __init__(self, baz: object = super()._BAR):
super().__init__(baz)
Unfortunately, this doesn't work. One gets an error: RuntimeError: super(): no arguments
Is there a way to use super outside of a method to get a parent class attribute?
The workaround is to use Foo._BAR, I am wondering though if one can use super to solve this problem.
Inside of DFoo, you cannot refer to Foo._BAR without referring to Foo. Python variables are searched in the local, enclosing, global and built-in scopes (and in this order, it is the so called LEGB rule) and _BAR is not present in any of them.
Let's ignore an explicit Foo._BAR.
Further, it gets inherited: DFoo._BAR will be looked up first in DFoo, and when not found, in Foo.
What other means are there to get the Foo reference? Foo is a base class of DFoo. Can we use this relationship? Yes and no. Yes at execution time and no at definition time.
The problem is when the DFoo is being defined, it does not exist yet. We have no start point to start following the inheritance chain. This rules out an indirect reference (DFoo -> Foo) in a def method(self, ....): line and in a class attribute _DBAR = _BAR.
It is possible to work around this limitation using a class decorator. Define the class and then modify it:
def deco(cls):
cls._BAR = cls.__mro__[1]._BAR * 2 # __mro__[0] is the class itself
return cls
class Foo:
_BAR = 10
#deco
class DFoo(Foo):
pass
print(Foo._BAR, DFoo._BAR) # 10 20
Similar effect can be achieved with a metaclass.
The last option to get a reference to Foo is at execution time. We have the object self, its type is DFoo, and its parent type is Foo and there exists the _BAR. The well known super() is a shortcut to get the parent.
I have assumed only one base class for simplicity. If there were several base classes, super() returns only one of them. The example class decorator does the same. To understand how several bases are sorted to a sequence, see how the MRO works (Method Resolution Order).
My final thought is that I could not think up a use-case where such access as in the question would be required.
Short answer: you can't !
I'm not going into much details about super class itself here. (I've written a pure Python implementation in this gist if you like to read.)
But now let's see how we can call super:
1- Without arguments:
From PEP 3135:
This PEP proposes syntactic sugar for use of the super type to
automatically construct instances of the super type binding to the
class that a method was defined in, and the instance (or class object
for classmethods) that the method is currently acting upon.
The new syntax:
super()
is equivalent to:
super(__class__, <firstarg>)
...and <firstarg> is the first parameter of the method
So this is not an option because you don't have access to the "instance".
(Body of the function/methods is not executed unless it gets called, so no problem if DFoo doesn't exist yet inside the method definition)
2- super(type, instance)
From documentation:
The zero argument form only works inside a class definition, as the
compiler fills in the necessary details to correctly retrieve the
class being defined, as well as accessing the current instance for
ordinary methods.
What were those necessary details mentioned above? A "type" and A "instance":
We can't pass neither "instance" nor "type" which is DFoo here. The first one is because it's not inside the method so we don't have access to instance(self). Second one is DFoo itself. By the time the body of the DFoo class is being executed there is no reference to DFoo, it doesn't exist yet. The body of the class is executed inside a namespace which is a dictionary. After that a new instance of type type which is here named DFoo is created using that populated dictionary and added to the global namespaces. That's what class keyword roughly does in its simple form.
3- super(type, type):
If the second argument is a type, issubclass(type2, type) must be
true
Same reason mentioned in above about accessing the DFoo.
4- super(type):
If the second argument is omitted, the super object returned is
unbound.
If you have an unbound super object you can't do lookup(unless for the super object's attributes itself). Remember super() object is a descriptor. You can turn an unbound object to a bound object by calling __get__ and passing the instance:
class A:
a = 1
class B(A):
pass
class C(B):
sup = super(B)
try:
sup.a
except AttributeError as e:
print(e) # 'super' object has no attribute 'a'
obj = C()
print(obj.sup.a) # 1
obj.sup automatically calls the __get__.
And again same reason about accessing DFoo type mentioned above, nothing changed. Just added for records. These are the ways how we can call super.
Pretty much what the title says but I will put some example code to clarify.
I would like to know why I can assign Repair, a reference to the class, to an instance variable but not to a class variable
class NotWorkingDefinitions:
# This will give unresolved reference
a = Repair
class WorkingDefitinions:
def __init__(self):
# This is fine
self.a = Repair
class Repair():
def __init__(self):
whatever = 10
def dosmt(self):
print("staring at a wall")
EDIT: The full answer is given over the different comments. It wasn't about not being able to assign to a class variable. It is just that class variables are immediately resolved and instance variables are not. The latter makes that defining Repair() class after WorkingDefinitions is not an issue.
The above code works if you move Repair to the top. The content of a class is evaluated from top to bottom, so any referenced classes must be defined before actually referencing them.
An example that explores this a bit more in terms of runtime and load-time could be:
# this will not work because the B class is referenced before definition
class A(object):
b_class = B
class B(object):
pass
Alternatively,
# this will work because B is defined first and used later
class B(object):
pass
class A(object):
b_class = B
But both of the examples above do not have a runtime-specific behavior. If instead you wanted A to use B and you had a really good reason to define A first, then you could get away with
class A(object):
def __init__(self):
# bind the B class to each instance of A
self.b_class = B
class B(object):
pass
a = A()
a.b_class
> __main__.B
But the short answer is you must define a variable before using it and when you bind a variable directly to a class (in the class definition, not a method) it must be defined.
The full answer is given over the different comments. It is not about not being able to assign to a class variable. It is that class variables are immediately evaluated and instance variables are not. Instance variables will be evaluated during initiation. The latter makes that defining Repair() class after WorkingDefinitions is not an issue.
In Python (2.7) one can use nested class declarations which is sometimes handy to organise local classes.
However, I can't figure out how to reference a class in a parent class so I can derive from it.
A minimal example is this:
class A(object):
class B(object):
pass
class C(object):
class D(A.B): # <-- fails with "NameError: name 'A' is not defined"
pass
How can I make class D derive from class B given the nested structure of the class declaration?
You can't. You can't reference it as A.B, because A is not yet defined (you are in the middle of the definition), and you can't reference it as B because as per PEP 227, names in class scope are not accessible:
Names in class scope are not accessible. Names are resolved in
the innermost enclosing function scope. If a class definition
occurs in a chain of nested scopes, the resolution process skips
class definitions. This rule prevents odd interactions between
class attributes and local variable access. If a name binding
operation occurs in a class definition, it creates an attribute on
the resulting class object. To access this variable in a method,
or in a function nested within a method, an attribute reference
must be used, either via self or via the class name.
An alternative would have been to allow name binding in class
scope to behave exactly like name binding in function scope. This
rule would allow class attributes to be referenced either via
attribute reference or simple name. This option was ruled out
because it would have been inconsistent with all other forms of
class and instance attribute access, which always use attribute
references. Code that used simple names would have been obscure.
That said, even if it was possible, this kind of definition looks really obscure and probably can be refactored into something simpler.
Edit: if you really, really want your class hierarchy look like this, you can just "monkey patch" A:
class A(object):
class B(object):
pass
class _C(object):
class D(A.B):
pass
A.C = _C
I am quite new to python, so pardon me for basic question. I tried google for past few days but could not make it in my program.
Can anyone show me a good example how can I use method from One class to another in python and what is significance of __init__ while defining class.
I am using python2.7
Thanks in anticipation.
To use a method defined in one class inside of another class, you have several options:
Create an instance of B from within one of A's methods, then call B's method:
class A:
def methodInA():
b = B()
b.methodInB()
If appropriate, use the concept of inheritance (one of the defining concepts of object-oriented design) to create a subclass of the original class whose method(s) you wish to use:
class B(A):
...
__init__() is a class initializer. Whenever you instantiate an object you are invoking __init__() whether or not it is explicitly defined. It's main purpose is to initialize class data members:
class C:
def __init__(self, name):
self.name = name
def printName(self):
print self.name
c = C("George")
c.printName() # outputs George
With __init__() defined, in particular with the additional argument name in this example, you are able to differentiate between would-be generically constructed instances by allowing for different initial states from instance to instance.
There are 2 issues here:
First: Using method of class A in class B, both classes in different files
class A:
def methodOfA(self):
print "method Of A"
let the above class be in file a.py Now the class B is supposed to be in b.py. Both a.py and b.py are assumed to be on the same level or in the same location. Then b.py would look like:
import a
class B:
def methodOfB(self):
print "Method of B"
a.A().methodOfA()
You can also do this by inherting A in B
import a
class B(a.A):
def methodOfB(self):
print "Method of B"
self.methodOfA()
there are several other ways to use A in B. I will leave it to you to explore.
Now to your second question. The use of __init__ in a class. __init__ is not a constructor, as popularly believed and explained above. It is, as the name suggests, an initialization function. It is called only after the object has already been constructed and it is implicitly passed the object instance as the first argument, as signified by self in its argument list.
The actual constructor in python is called __new__, which does not need a object to call it. This is actually a specialized Static method, which receives the class instance as the first argument. __new__ is exposed for overwriting only if the class inherits form the object base class of python
Whatever other arguments are passed while creating an object of a class, first go to __new__ and then are passed with the object instance to the __init__, if it accepts them.
The init function is what is called a constructor function. When you create an instance of a class object = myClass(), init is the function that is automatically called. i.e.
That being said, to call a function from one class to another, you need to call an instance of the second class inside the first one, or vice versa. for eg.
class One():
def func(self):
#does sometthing here
class Two():
def __init__(self):
self.anotherClass = One()
#Now you can access the functions of the first class by using anotherClass followed by dot operator
self.anotherClass.func()
#When you call the main class. This is the time the __init__ function is automatically called
mainClass = Two()
Another way to access from another class is the use of oop concept called Inheritance.
class One():
def __init__(self):
print('Class One Called')
def func(self):
print('func1 Called')
class Two(One):
def __init__(self):
One.__init__(self,) #This basically creates One's instance
print('Main Called')
c= Two()
c.func()
The output for this is:
Class One Called
Main Called
func1 Called