I've the following code:
class PageElement:
def __init__(self, a, b):
self.a = a
self.x = b
@property
def prop(self):
print(f"{self.x}")
return 1
class Tag(PageElement):
def __init__(self, a, b):
self.a = a
self.b = b
def __getattr__(self, x):
self.x = x
print("Tag.getattr was invoked")
t = Tag(3, 4)
print(t.prop)
it outputs
Tag.getattr was invoked
None
1
I checked t.__dict__ to be {'a': 3, 'b': 4, 'x': 'x'}, but still the value of t.x (='x') is not printed when print(f"{self.x}") is executed in the source code. I can't understand how on Earth f"{self.x}" is getting evaluated to None. Kindly help.
CodePudding user response:
You need to call init of PageElement (SuperClass), when you try to print
print(f"{self.x}")
Your self.x is undefined because you don't call constructor of SuperClass (PageElement). You can add this call to SubClass (Tag)
class PageElement:
def __init__(self, a, b):
self.a = a
self.x = b
@property
def prop(self):
print(f"{self.x}")
return 1
class Tag (PageElement):
def __init__(self, a, b):
self.a = a
self.b = b
super().__init__(self.a, self.b)
def __getattr__(self, x):
self.x = x
print("Tag.getattr was invoked")
t = Tag(3, 4)
print(t.prop)
CodePudding user response:
I think that several misconceptions about Python's data model are involved here.
__getattr__should return an attribute. In this code it assigns the named of the accessed attribute (the argument that it receives) to thexattribute__getattr__is only being called when the accessed attribute does not exist on the instanceSubclasses should almost always explicitly call the parent's class
__init__method.
Due the first 2 points, any subsequent calls to Tag.prop will in fact output x:
t = Tag(3, 4)
print(t.prop)
print(t.prop)
outputs
Tag.getattr was invoked
None
1
x
1
This is because on the first call to t.prop, x does not exist on t (because PageElement.__init__ was never called). This triggers the call to Tag.__getattr__ that assigns x but never returns it. This is where the None comes from.
On the second call to t.prop, x does exist so __getattr__ is not called (so None is not returned from any where). Because x does exist now, prop can print it and it prints x.
All of this is unnecessarily over-engineered , and instead you should just be calling PageElement.__init__ from Tag.__init__:
class PageElement:
def __init__(self, a, b):
self.a = a
self.x = b
@property
def prop(self):
print(f"{self.x}")
return 1
class Tag(PageElement):
def __init__(self, a, b):
super().__init__(a, b)
t = Tag(3, 4)
print(t.prop)
This outputs
4
1
