error when using method defined parent class - python

I have the following classes:
class A:
def name(self):
return self.__label
class B(A):
def __init__(self, name)
self.__label = name
ex1 = B('Tom')
print ex1.name()
What I get is:
AttributeError: B instance has no attribute '_A__label'
What's wrong and how to correct it?

When you prefix an attribute with a double underscore, Python uses 'name mangling' to access the attribute. This means it will store the attribute on the class in the format: _<class name>__<attr name>. In your example self.__label will be stored as self._B__label because you set it in the B class method. But when you try to use the attribute in the A class it converts self.__label into self._A__label and finds that it isn't set.
The use case for double underscores is when you want to ensure that your variable is always on your class even if a subclass derives your class. Because what could happen is that the subclass redefines your variable to something else, using double underscored variables makes this that much harder.

Related

Get python class's namespace parent type

Is it possible to get the the namespace parent, or encapsulating type, of a class?
class base:
class sub:
def __init__(self):
# self is "__main__.extra.sub"
# want to create object of type "__main__.extra" from this
pass
class extra(base):
class sub(base.sub):
pass
o = extra.sub()
The problem in base.sub.__init__ is getting extra from the extra.sub.
The only solutions I can think of at the moment involve having all subclasses of base provide some link to their encapsulating class type or turning the type of self in base.sub.__init__ into a string an manipulating it into a new type string. Both a bit ughly.
It's clearly possible to go the other way, type(self()).sub would give you extra.sub from inside base.sub.__init__ for a extra type object, but how do I do .. instead of .sub ? :)
The real answer is that there is no general way to do this. Python classes are normal objects, but they are created a bit differently. A class does not exist until well after its entire body has been executed. Once a class is created, it can be bound to many different names. The only reference it has to where it was created are the __module__ and __qualname__ attributes, but both of these are mutable.
In practice, it is possible to write your example like this:
class Sub:
def __init__(self):
pass
class Base:
Sub = Sub
Sub.__qualname__ = 'Base.Sub'
class Sub(Sub):
pass
class Extra(Base):
Sub = Sub
Sub.__qualname__ = 'Extra.Sub'
del Sub # Unlink from global namespace
Barring the capitalization, this behaves exactly as your original example. Hopefully this clarifies which code has access to what, and shows that the most robust way to determine the enclosing scope of a class is to explicitly assign it somewhere. You can do this in any number of ways. The trivial way is just to assign it. Going back to your original notation:
class Base:
class Sub:
def __init__(self):
print(self.enclosing)
Base.Sub.enclosing = Base
class Extra(Base):
class Sub(Base.Sub):
pass
Extra.Sub.enclosing = Extra
Notice that since Base does not exist when it body is being executed, the assignment has to happen after the classes are both created. You can bypass this by using a metaclass or a decorator. That will allow you to mess with the namespace before the class object is assigned to a name, making the change more transparent.
class NestedMeta(type):
def __init__(cls, name, bases, namespace):
for name, obj in namespace.items():
if isinstance(obj, type):
obj.enclosing = cls
class Base(metaclass=NestedMeta):
class Sub:
def __init__(self):
print(self.enclosing)
class Extra(Base):
class Sub(Base.Sub):
pass
But this is again somewhat unreliable because not all metaclasses are an instance of type, which takes us back to the first statement in this answer.
In many cases, you can use the __qualname__ and __module__ attributes to get the name of the surrounding class:
import sys
cls = type(o)
getattr(sys.modules[cls.__module__], '.'.join(cls.__qualname__.split('.')[:-1]))
This is a very literal answer to your question. It just shows one way of getting the class in the enclosing scope without addressing the probably design flaws that lead to this being necessary in the first place, or any of the many possible corner cases that this would not cover.

Getting the name of a class which has a meta class

Suppose I define a class A with a meta class like this:
class Meta(type):
pass
class A(metaclass=Meta):
pass
Then, when I try to access the name of class A I get the name of the meta class:
A.__class__.__name__
# 'Meta'
However, shouldn't it give me A, my defined class?
Note: I tried to use A.__mro__[0].__name__ and it does give me A, but I am still confused why A.__class__ gives me the meta class name. Does anyone has an explanation of this?
The __class__ dunder reports:
the class to which a class instance belongs.
Quote from instance.__class__
The class A belongs to the class of it's metaclass - only instances of A belong to the class A itself.
a = A()
print(a.__class__.__name__) # 'A'
print(A.__class__.__name__) # 'Meta'
class P: pass
print(P.__class__.__name__) # type
print(P().__class__.__name__) # P
To get the name of the class itself simply use
A.__name__
if you really need it.
I am still a way to groke all of answer to What are metaclasses in Python? - maybe it helps you out.
A is already the class - its name is under A.__name__.
If you try A.__class__.__name__ you will get to the class of which A is instance (that is, its metaclass), name.
A.__mro__[0].__name__ will follow the "method resolution order" for the class A - the __mro__ object is a tuple with all the class hyerarchy that starts in the defined class itself and ends in object. So, A.__mro__[0] will always be A itself - and A.__mro__[0].__name__ is the same as A.__name__.
The __name__ and __qualname__ attributes are writable attributes: changing { __qualname__ after the class is created will change the default __repr__ for instances of that class, for example. Although they are in the language definition and "live" in slots in the class (not on it's dictionary), it is possible to create a __name__ property (I mean, the built-in property object, or any other descriptor) on the metaclass that will dynamically change the __name__ attribute of a class (but not __qualname__ - this must be an attribute of the class, and must be a string)

Calling a method from a parent class in Python

Can anyone help me with the correct syntax to call my method __get_except_lines(...) from the parent class?
I have a class with a method as shown below. This particular method has the 2 underscores because I don't want the "user" to use it.
NewPdb(object)
myvar = ...
...
def __init__(self):
...
def __get_except_lines(self,...):
...
In a separate file I have another class that inherits from this class.
from new_pdb import NewPdb
PdbLig(NewPdb):
def __init__(self):
....
self.cont = NewPdb.myvar
self.cont2 = NewPdb.__get_except_lines(...)
And I get an attribute error that really confuses me:
AttributeError: type object 'NewPdb' has no attribute '_PdbLig__get_except_lines'
Your problem is due to Python name mangling for private variable (http://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references). You should write:
NewPdb._NewPdb__get_except_lines(...)
super(<your_class_name>, self).<method_name>(args)
e.g.
super(PdbLig, self).__get_except_lines(...)
The entire point of putting a double underscore in front of a name is to prevent it from being called in a child class. See http://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
If you want to do this, then don't name it with a double underscore (you can use a single underscore), or create an alias for the name on the base class (thus again defeating the purpose).

Python property not working

I have an object which inherits from ndb.Model (a Google App Engine thing). This object has a property called commentid:
class Comment(ndb.Model):
commentid = ndb.StringProperty()
Reading a bunch of articles, they all say this is the way to implement a property:
#property
def commentid(self):
if not self._commentid:
self._commentid = "1"
return self._commentid
but I get an error saying Comment object has no attribute _commentid. What am I doing wrong?
Edit: Ok obviously I'm a bit confused here. I come from Objective-C, where if you have a property called x then you automatically get a variable called _x in your getters and setters. So I thought this is what was happening here in Python too. But apparently I need to manually set a value for the variable with an underscore prefix.
All I want is to implement a getter where I do some checking of the value before returning it. How would I do this?
Implementing a property like that requires you to define the attribute for your object. What you're doing there, is defining a class called Comment but you don't define any attributes for it's objects, you define them for the class itself.
Let me demonstrate with a small example:
class ExampleClass:
name = "Example Object"
a = ExampleClass() # Init new instance of ExampleClass
print(a.name) # a doesn't own an attribute called "name"
print(ExampleClass.name) # --> "Example Object"
In the above example, I define class ExampleClass and give it a variable name with a value Example Object. After that, I create an object a = ExampleClass(), however it does not get the name attribute, cause the attribute is defined for the class itself, not for it's objects.
To fix this problem, you define the name inside __init__ -method, which gets called whenever an object of that class is created.
class ExampleClass:
def __init__(self):
self.name = "Example Class"
a = ExampleClass() # Init new instance of ExampleClass
print(a.name) # --> "Example Class"
print(ExampleClass.name) # --> ERROR: Exampleclass.name doesn't exist
There I define the ExampleClass again, but I also define __init__ method for it. Init method takes only one parameter, self, which will be automatically given to the function. It's the object which is being created. Then I set self.name = "Example Class", and since self is the object itself, we set the object's attribute name.
Creating the property
To implement setter and getter for your attribute, you add the following:
class ExampleClass:
def __init__(self):
self.name = "Example Class"
#property
def name(self):
if not self._name:
pass #blabla code here
return self._name
#name.setter
def name(self, value):
#blabla more code
self._name = value
Also, you should edit the __init__ method to take name as a parameter too.
def __init__(self, name="Example Object"):
self.name = name
If you access self._commentid directly, it needs to be defined or it'll raise an exception. Since you're instead checking if _commentid is defined at all (to give it a default value), I'd use hasattr:
#property
def commentid(self):
if not hasattr(self, "_commentid"):
self._commentid = "1"
return self._commentid

Calling private parent class method from parent class (django)

I want to call a redefined private method from an abstract parent class. I am using django if that matters.
class Parent(models.Model):
def method1(self):
#do somthing
self.__method2()
def method2(self):
pass # I also tried calling up a prent method with super
class child(Parent):
def method1(self)
super(Child, self).method1()
def __method2(self):
#do something
I get a
AttributeError: "'Chil' object has no attribute '_Parent__method2'"
What I am doing wrong ?
Initial double underscores prevent polymorphism since both the method definition and the method call get mangled, to two different names. Replace with a single underscore to fix this.
Also, double underscores are not used for "private" attributes, and you should discard whatever reference told you that they are. They're used for MI disambiguation.

Categories