-1

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:

  1. getattr() takes no keyword arg, as the ErrorType returns.

  2. I don't exactly know how to implement "ANY of the attributes". I thought dict could be a good way.

  3. 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)

Richard
  • 721
  • 5
  • 16
  • 1
    Can you clarify your code? `name` or `other` are not defined anywhere. So what is `name = name` and `other = other` in `B`, `C` or `D`? Can you use example values if need be? When you say "from WHATEVER object has it" do you mean a specific attribute (such as `name`) or any of them? – 301_Moved_Permanently Sep 06 '15 at 21:46
  • 1
    I don't know what is a global method, maybe you mean a global function here explanation of what is the difference between function (GlobalMethod() is a function actually) and a method : http://stackoverflow.com/questions/155609/difference-between-a-method-and-a-function – Richard Sep 06 '15 at 21:49
  • 1
    Improving your question could help you having an answer... Here how to ask a good question : http://stackoverflow.com/help/how-to-ask – Richard Sep 06 '15 at 21:51
  • Also you say "from WHATEVER object B, C or D" but those are classes. (And I don't think you're accounting from the fact that classes are objects too.) So which one is it, are you interested by B, C and D _instances_? – 301_Moved_Permanently Sep 06 '15 at 21:51
  • Name is the class's name (redundant, I know, but I need it for later calling), Other could be a class's attribute like Origin. When I say "from WHATEVER object has it", I mean " given the value provided, get the attribute which contains that value and also return the object that has that attribute containing the specified value". So yes, I'd say any of them. – roby.cogitans Sep 06 '15 at 21:52
  • So name is a string. And it is the string you are looking for in other instances when not found into the one you pass to the function ?? – 301_Moved_Permanently Sep 06 '15 at 21:56
  • Thanks Richard for those links, I'll read them carefully. As GlobalMethod I mean a function that has a the whole module as its scope, not limited to particular classes – roby.cogitans Sep 06 '15 at 21:59
  • I think I'm getting what you are trying to achieve. But I have the feeling that's a form of an [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Instead, what are you trying to solve with this approach? – 301_Moved_Permanently Sep 06 '15 at 22:06
  • @MathiasEttinger, yes Name is a string, and also Other would be a string. None of them are necessarily attributes that I'm looking for when not found into the one I pass. The idea is: I have an attribute value, but I don't know what attributes all of the classes may have. But I also know that this attribute value is inside any attribute of any class. I want to know which class and which attribute has that value, if not found in the class I pass in the function – roby.cogitans Sep 06 '15 at 22:07
  • I'm trying to write an Attribute Mapping function. I want a very general function which can be run on any kind of class and attributes. Attributes should be mapped from one class to another, without overwriting the class's default value, just temporarily returning the mapped one. (hope I'm clear enough, not sure) – roby.cogitans Sep 06 '15 at 22:14

1 Answers1

-1

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

Update to react to comments and clarify between attributes and class attributes

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.

301_Moved_Permanently
  • 4,007
  • 14
  • 28
  • This is already great! I'll try to fit it and work the thing out, and let you know! Thanks you very much! – roby.cogitans Sep 06 '15 at 22:25
  • @roby.cogitans Don't use `globals()` ever, kind of in the same way you don't do kidney transplants without years of practice. – msw Sep 06 '15 at 22:29
  • @mws What is so wrong with using `globals()` read only? It doesn't seems like OP will be using this function from another module. Well I might be wrong and changed the answer accordingly. – 301_Moved_Permanently Sep 06 '15 at 22:54
  • @MathiasEttinger. I'm working on the code you gave me (thank you again for help). You said you're "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__.)" – roby.cogitans Sep 12 '15 at 13:48
  • But what if I wanted the pool of A to be filled with subclasses? In my original code I was probably misleading: I wanted A to be a superclass and B, C, D to be subclasses (with default attributes values), which will have instances in turn. So that when I pass values, if these don't match the default values for each subclass, I want to have the object and the attribute which contain the passed value returned. (again, hope I'm clear enough). Thanks! – roby.cogitans Sep 12 '15 at 13:48
  • See my updated answer. Anyway, if it is of any use to you, consider upvoting and/or accepting the answer, thanks – 301_Moved_Permanently Sep 12 '15 at 15:18