-2

In Python 2.7, I have the following example classes defined:

class A:
    def __init__(self):
        self.a = 1
        self.b = 3

class B(A):
    def __init__(self):
        A.__init__(self)
        self.a = 1

obj_b = B()
print(vars(obj_b))

Object obj_b now has both a and b. Although a has the same value as in class A, it's been reassigned in class B.
Is there any way to tell if a is reassigned in class B?

james
  • 1,107
  • 14
  • 29
  • 1
    What's the context in which you'd need to know? – jonrsharpe Nov 30 '20 at 21:32
  • @jonrsharpe it's just out of curiosity. I'd like to know if this is possible to do and how to do it. – james Nov 30 '20 at 21:36
  • 2
    Curiosity isn't a good fit for the "practical, answerable" requirement for SO questions. The point of inheritance/polymorphism/duck typing is that it doesn't matter where the attributes come from, just that the object has them. – jonrsharpe Nov 30 '20 at 21:37
  • 1
    `a` has not been overridden in class `B`. It's been reassigned. There's nothing special about the use of a subclass here. "Overriding" applies to methods and properties, not to ordinary slots. – Silvio Mayolo Nov 30 '20 at 21:41
  • 1
    @jonrsharpe How would you define "practical"? Does it have to be a real world problem? I see plenty of posts asking about programming language features and they are very similar to this question. Regarding "answerable" - if you don't have an answer, someone else may have it. – james Nov 30 '20 at 21:45
  • @SilvioMayolo yeah, I see what you mean, thanks, so is there any way to check if such reassignment happened in class B's constructor? – james Nov 30 '20 at 21:50
  • @james only if *you* add that check in the code you've written. The object doesn't keep track of the context in which an attribute has been assigned/re-assigned (or even that it *has* been re-assigned). – juanpa.arrivillaga Nov 30 '20 at 21:51
  • 1
    The advantage of a real world problem (once we get past the [XY parts](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), at least) is it has goals and constraints, letting readers figure out whether it applies to their context and answerers suggest other ways to achieve those goals within those constraints, whereas curiosity is open ended. You could do this by looking at the code or the AST, for example, but that's not likely to be practical in a real app. – jonrsharpe Nov 30 '20 at 21:56
  • I understand your point, @jonrsharpe but curiosity about a programming language's feature and its limit is a great way of learning and should not be discouraged. This question certainly has a clear goal - to check if an attribute is reassigned (I used the word "overridden" but clarified it in the comment) The constraints are shown in the code and explained in the comment above, I'd like to check reassignment in the constructor. – james Nov 30 '20 at 22:08
  • I'm not trying to discourage it, curiosity is great, I'm just saying it's not a good fit *for SO questions*. Checking if an attribute is reassigned is a *means*, not an end - if you have an actual goal, you haven't told us what it is. – jonrsharpe Nov 30 '20 at 22:11
  • My actual goal IS to check if an attribute is reassigned, because I'm simply just curious if this is possible. – james Nov 30 '20 at 22:13

2 Answers2

1

yeah, I see what you mean, thanks, so is there any way to check if such reassignment happened in class B's constructor?

Answering a question from the comments, this can certainly be done. It's not foolproof, in the sense that a programmer can go out of their way to cheat your system, but they have to do so on purpose.

We just need to make a a property.

class A:
    def __init__(self):
        self._a = 1
        self.was_a_changed = False

    @property
    def a(self):
        return self._a

    @a.setter
    def a(self, x):
        self._a = x
        self.was_a_changed = True

class B(A):
    def __init__(self):
        self.a = 1

class C(A):
    pass

obj_a = A()
obj_b = B()
obj_c = C()
print(obj_a.was_a_changed) # False
print(obj_b.was_a_changed) # True
print(obj_c.was_a_changed) # False

Now a isn't a real value; it's a property which is backed by the actual value _a. But if a subclass reassigns a, it'll make a note so that we can check whether it's been touched later.

If someone wants to cheat your system, they can always assign directly to self._a rather than self.a, but that would be unidiomatic Python to assign to a private you don't own anyway.

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
0

If a is a class attribute, rather than an instance attribute, this question would make more sense. An instance of A (possibly a subclass) could compare self.__class__.a against A.a. As is you could potentially compare self.a against A().a, but there's no way to distinguish between changes made during initialization and changes made at any other point.

JoshuaF
  • 1,124
  • 2
  • 9
  • 23