class Test(object):
def __init__(self):
pass
def testmethod(self):
# instance method
self.task(10) # type-1 access class method
cls = self.__class__
cls.task(20) # type-2 access class method
#classmethod
def task(cls,val)
print(val)
I have two way to access class method into instance method.
self.task(10)
or
cls = self.__class__
cls.task(20)
My question is which one is the best and why??
If both ways are not same, then which one I use in which condition?
self.task(10) is definitely the best.
First, both will ultimately end in same operation for class instances:
__class__ is a special attribute that is guaranteed to exist for an class instance object and is is the class of the object (Ref: Python reference manual / Data model / The standard type hierarchy)
Class instances ...Special attributes: __dict__ is the attribute dictionary; __class__ is the instance’s class
calling a classmethod with a class instance object actually pass the class of the object to the method (Ref: same chapter of ref. manual):
...When an instance method object is created by retrieving a class method object from a class or instance, its __self__ attribute is the class itself
But the first is simpler and does not require usage of a special attribute.
Related
class Test:
def __init__(self):
print('Object reference:', id(self))
print('Class object reference', id(Test))
t = Test()
Object reference: 2170838573008
Class object reference: 2170806511808
It is not the same as class name. Everything is an object in Python. Classes are, and their instances, too. Even modules, and functions, just everything.
Class Name is not same as class object. When you create an instance of class that time you create an object for that class. In your case t is a Object of class Test.
Almost everything is object in python. So as your class is a type of object.
class Test:
def __init__(self):
print('Object reference:',id(self))
print('Class object reference',id(Test))
t = Test() // Here t is object of class Test.
when you use class keyword, you are actually creating an instance of type type. Classes are instances themselves.
class Test:
pass
print(isinstance(Test, type)) # True
print(type(Test)) # <class 'type'>
here, Test is just a label in your global namespace, which points to this instance you have created.
Now when you call your class, here Test, you are creating an instance of it. self inside your class, points to this object (instances of your class).
I am trying to inject a mixin to a class with a decorator. When the code runs the class no longer has a dict property even though the dir(instance) says it has one. I'm not sure where the property is disappearing. Is there a way that I can get dict or otherwise find the instance's attributes?
def testDecorator(cls):
return type(cls.__name__, (Mixin,) + cls.__bases__, dict(cls.__dict__))
class Mixin:
pass
#testDecorator
class dummyClass:
def __init__(self):
self.testVar1 = 'test'
self.testVar2 = 3.14
inst = dummyClass()
print(dir(inst))
print(inst.__dict__)
This code works if the decorator is commented out yet causes an error when the decorator is present. Running on python 3.5.1
It's not "losing __dict__". What's happening is that your original dummyClass has a __dict__ descriptor intended to retrieve the __dict__ attribute of instances of your original dummyClass, but your decorator puts that descriptor into a new dummyClass that doesn't descend from the original.
It's not safe to use the original __dict__ descriptor with instances of the new class, because there's no inheritance relationship, and instances of the new class could have their dict pointer at a different offset in their memory layout. To fix this, have your decorator create a class that descends from the original instead of copying its dict and bases:
def testDecorator(cls):
return type(cls.__name__, (Mixin, cls), {})
So, here's the problem..
if you do this:
class x(object):
def __init__(self):
pass
why would you explicitly call init in child class to access parent class attribute? (class y has class x attribute anyway.)
class y(x):
def __init__(self):
x.__init__(self)
Cheers.
Edit:
I read this article https://linuxmeerkat.wordpress.com/2015/04/28/why-you-should-use-super-in-python/, it says "In real life we tend to run the initializer for every parent class. This is simply because of how program designs tend to be. In our simple example a way to solve this is to explicitly call the initializer of A:" Could someone please explain?
The fact is that in python there is a clear distinction between class and instance attributes:
Attributes declared in the class body, outside any method, are class attributes, they are the same for each object of that class and are the ones that are inherited by the subclasses. Be aware of the fact that doing instance_obj.class_att = something doesn't change the value of the class attribute, but simply creates an instance attribute and hides the shared class attribute for that object.
Instance attributes are the ones that are declared with syntax instance_obj.att = something, they are not shared between instances and are the most similar thing to non-static attributes that you have in other programming languages and they are usually created in the init method.self is just a convention to indicate the instance object automatically passed to methods.
Here's an example:
class MyClass:
c = 1 #class attribute, the subclasses will inherit this
def __init__(self):
self.i = 1 #instance attribute
MyClass.c #access attribute c of class MyClass
MyClass.i #error! MyClass has no attribute i
x = MyClass() #calling __init__ creates instance attribute i for obj x
x.i #access instance attribute i of object x
x.c #access class attribute c of class MyClass
x.c = 2 #hide MyClass.c and create instance attribute c for obj x
x.c #access instance attribute c of obj x
So, to sum up, doing:
class y(x):
def __init__(self):
x.__init__(self)
is useful because if the base class would have been something like this
class x:
def __init__(self):
self.i=1
you would have not been able to access the attribute i from any instances of y simply because they would not have it.
Instead of calling to the init function explicitly, you should use the super() method instead.
In python 3.0+, you can jusy use:
class y(x):
def __init__(self):
super().__init__()
In python 2.7 or under, use:
class y(x):
def __init__(self):
super(self.__class__, self).__init__()
super() lets you avoid referring to the base class explicitly.
Because the child class inherits from the parent class, of course, that means everything: methods, attributes and the constructor.
So instead of rewrite all the __init__ code, you just use what is already written in the parent class.
Hope it makes sense to you.
I am getting an exception when I try to access a base class's property using super(), but not when I use the base class name explicitly. Here is the derived class:
from CPSA_TransactionLogOutSet import CPSA_TransactionLogOutSet
class CPSA_TransactionFailureSet(CPSA_TransactionLogOutSet):
def __init__(self, connection, failedTransactionKey):
super().__init__(connection)
CPSA_TransactionLogOutSet.C_TRANS_TYP = "TRANS_FAIL"
super().C_TRANS_TYP = "TRANS_FAIL"
super().DefaultTableName = 'CPSA_TRANSACTION_LOG_IN'
super()._keyFields.append('J_TRANS_SEQ')
but trying to create an instance raises an AttributeError exception:
AttributeError: 'super' object has no attribute 'C_TRANS_TYP'
The base class consists of an __init__() method and a set of properties, only one of which is shown here:
class CPSA_TransactionLogOutSet(Recordset):
def __init__(self, connection):
super().__init__(connection)
self.DefaultTableName = 'CPSA_TRANSACTION_LOG_OUT'
#property
def C_TRANS_TYP(self):
return self.GetValue('C_TRANS_TYP')
#C_TRANS_TYP.setter
def C_TRANS_TYP(self, value):
self.SetValue('C_TRANS_TYP', value)
Why can't I use super() to access the C_TRANS_TYP property?
You don't need to use super() at all because there is no override on the current class. The descriptor will be bound to self without super(). The same applies to the other attributes on self:
def __init__(self, connection, failedTransactionKey):
super().__init__(connection)
self.C_TRANS_TYP = "TRANS_FAIL"
self.DefaultTableName = 'CPSA_TRANSACTION_LOG_IN'
self._keyFields.append('J_TRANS_SEQ')
super() is only needed to access descriptors that would not otherwise be reachable via self. The normal access path (via the instance) suffices here.
super() can't be used to bind data descriptors in an assignment or del obj.attr statement, because super() objects do not implement __set__ or __delete__. In other words, using super().attribute works for reading the attribute only, never for writing or deleting.
Setting CPSA_TransactionLogOutSet.C_TRANS_TYP is also incorrect; that replaces the descriptor object on the class. By executing that line, you removed the descriptor from the class hierarchy altogether, so neither self.C_TRANS_TYP nor super().C_TRANS_TYP would trigger the property you defined before.
I understand how to initialize a parent class to get their instance attributes in a child class, but not exactly what's going on behind the scenes to accomplish this. (Note: not using super intentionally here, just to make illustration clear)
Below we extend class A by adding an extra attribute y to the child class B. If you look at the class dict after instantiating b=B(), we rightfully see both b.x(inherited from class A) and b.y.
I assume at a high level this is accomplished by the call to A.__init__(self,x=10) performing something similar to b.x=10 (the way a normal instance attribute would be assigned) within the __init__ of class B. It's a bit unclear to me because you are calling the __init__ of class A, not class B, yet class B still gets it's instance attributes updated accordingly. How does class A's __init__ know to update b's instance attributes.
This is different than inherited methods where the b object has no explicit inherited method in it's particular namespace, but looks up the inheritance chain when a call to a missing method is made. With the attribute, the method is actually in b's namespace (it's instance dict).
class A:
def __init__(self,x):
self.x = x
class B(A):
def __init__(self):
A.__init__(self,x=10)
self.y = 1
b = B()
print(b.__dict__)
>>>{x:10,y:1} #x added to instance dict from parent init
Below we inherit from the built-in list. Here, similar to the above, since we are calling the list's __init__ method within Foolist's __init__, I would expect to see an instance dictionary that contains elems, but it is nowhere to be found. The values 123 are in the object somewhere, as can be seen by printing alist, but not in the instance dict.
class Foolist(list):
def __init__(self, elems):
list.__init__(self, elems)
alist = Foolist('123')
So what exactly is going on in the inheriting class when a parent's __init__ is called from a child's __init__? How are values being bound? It seems different from method lookup, as you are not searching the inheritance chain on demand, but actually assigning values to the inheriting class's instance dict.
How does a call to a parents init fill out it's child's instance dict? Why does the Foolist example not do this?
The answer is simple: self.
As a very rough overview, when instantiating a class, an object is created. This is more or less literally just an empty container without affiliation to anything.* This "empty container" is then passed to the __init__ method of the class that is being instantiated, where it becomes... the self argument! You're then setting an attribute on that object. You're then calling a different class's __init__ method, explicitly passing your specific self object to that method; that method then adds another attribute to the object.
This is in fact how every instance method works. Each method implicitly receives the "current object" as its first argument, self. When calling a parent's __init__ method, you're actually making that object passing very explicit.
You can approximate that behaviour with this simple example:
def init_a(obj):
obj.x = 10
def init_b(obj):
init_a(obj)
obj.y = 20
o = {}
init_b(o)
* The object is not entirely "empty", there are particular attributes set on the object which create an affiliation with a particular class, so the object is "an instance of" a certain class, and Python can locate all the methods it so inherits from the class as needed.