I'm a newbie with python, and would really appreciate your help with my issue.
I have a class A and three subclasses B, C, D, which all inherit from A - like this.
class A:
def __init__(self, arg1, arg2, arg3):
self.attr1 = B
self.attr2 = C
self.attr3 = D
class B(A):
name = name
other = other
class C(A):
name = name
other = other
class D(A):
name = name
other = other
I want to write a global method which has this meaning: "If the input attribute is not equal to ANY of the attributes listed in the specified Object, then take the input attribute from WHATEVER Object B, C, D has it". I thought I could implement the code like this.
def GlobalMethod(self, input):
if input != self.__dict__:
getattr(A, name=input)
print('attribute found here:'+getattr(self.name))
else:
print('attribute not found')
After assigning instances to subclasses
b = B()
c = C()
d = D()
I'd eventually pass the values like this (for sake of the example, I'll only write one instance)
GlobalMethod(b, 'big bang')
Main problems:
getattr() takes no keyword arg, as the ErrorType returns.
I don't exactly know how to implement "ANY of the attributes". I thought dict could be a good way.
I don't exactly know how to implement "from WHATEVER Object B, C, D has it"
Thank you in advance for helping! (and sorry if my description and code are quite messy)
If you are looking for an attribute value within an instance of A
, you can simply put all of them in a pool and scan it to fetch a matching object.
So:
class MappingPool:
def __init__(self):
self.pool = []
def add_scannable_object(self, obj):
self.pool.append(obj)
def search(self, some_value):
for obj in self.pool:
for attr in obj.__dict__:
if getattr(obj, attr) == some_value:
return obj
Should return the first object found containing an attribute matching the desired value. I'm limiting the search to instances atrributes and not including class attributes because you seem to only be interested in those. (Those defined in A.__init__
.)
To use it:
mapping = MappingPool()
b = B('a','b','c')
c = C('test','d','e')
d = D('f','g','h')
mapping.add_scannable_object(b)
mapping.add_scannable_object(c)
mapping.add_scannable_object(d)
x = mapping.search('test') # x is now an alias to c
You’re are not restricted about the objects you put into the mapping pool. For what it’s worth, you can put anything that has a __dict__
attribute in it. Any class and any instance of any class are suitable. I.e. if in addition to your A
, B
, C
and D
classes you define:
class Test:
where_is_it = 5
def __init__(self):
it_is_here = 9
then, you can add any instance of Test
to the same MappingPool
you used to put b
, c
, and d
as show above. Thus:
mapping = MappingPool()
b = B('a','b','c')
c = C('test','d','e')
d = D('f','g','h')
test = Test()
mapping.add_scannable_object(b)
mapping.add_scannable_object(c)
mapping.add_scannable_object(d)
mapping.add_scannable_object(test)
x = mapping.search(9)
print(x is test) # prints True
What I wanted to warn about when saying that the search is not including class attributes is that, using the setup just above, mapping.search(5)
returns None
even though test.where_is_it
is 5
.
This is due to the fact that instance variables and class variables are defined in two different namespaces and using obj.__dict__
returns only the namespace of the instance.
You can convince yourself by typing test.__dict__
which returns {'it_is_here': 9}
. So where did the where_is_it
attribute go? In the class namespace, since it’s defined at the class level:
>>> test.__class__.__dict__
mappingproxy({'__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None, '__init__': <function Test.__init__ at 0x7f4bf6f09d08>, '__module__': '__main__', 'where_is_it': 5})
Thus if you need to take into account both instance attributes and class attributes of the objects you are scanning, then you need to combine both:
from itertools import chain
for attr in chain(test.__dict__, test.__class__.__dict__):
print(attr)
outputs:
it_is_here
__dict__
__weakref__
__doc__
__init__
__module__
where_is_it
Conclusion, just replace for attr in obj.__dict__:
by for attr in chain(obj.__dict__, obj.__class__.__dict__):
if you want to support class attributes on top of instances attributes.