Check if an attribute is reassigned in derived class - python

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?

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.

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.

Related

Upcast instance to parent class in python

(How) Is it possible in Python to treat an instance of class B exactly as an instance of class A, where A is a parent of B (like up-casting in compiled languages)?
Say we have the following:
class A:
def __init__(self, prop=None):
self.prop = prop
def f(self):
return 'A.f'
def g(self):
return 'A.g', self.f()
class B(A):
def f(self):
return 'B.f'
def g(self):
return 'B.g', self.f()
Calling A().g() produces ('A.g', 'A.f'), whereas B().g() produces ('B.g', 'B.f'). Calling super(B, B()).g() produces ('A.g', 'B.f'), which is different from compiled languages, so I cannot use super. Instead, I need a function that changes the type from which an instance's methods are resolved, but preserves (a reference to) the original state. In short, I'm looking for a way to do this:
b = B(object())
a = upcast(b, A)
a.prop = object()
assert isinstance(a, A)
assert a.g() == ('A.g', 'A.f')
assert a.prop is b.prop
The closest I could get is
a = copy.copy(b)
a.__class__ = A
a.__dict__ = b.__dict__
(assuming A/B are "nice" "heap" classes), but this makes unnecessary copies of all objects in the __dict__ before I discard them. Is there a better way to do this?

Identify the superclass that defines a class-level variable

In the case of multiple inheritance in python, is there a way to identify which super class a class-level variable is obtained from?
All attempts I tried to google are overwhelmingly about How to get the attribute not find out where it came from:
https://www.google.com/search?q=pythin+which+super+class+defines+attr
https://www.google.com/search?q=python+which+super+class+has+attribute&oq=python+which+super+class+has+attr
https://www.google.com/search?q=python+which+super+class+attribute+obtained+from
I suppose I can manually step through the MRO using inspect.getmro(cls). But I couldn't find any more elegant solutions. Just wondering if anyone knows of one.
EDIT
For a concrete example:
class Super1(object):
__class_attribute__ = "Foo"
class Super2(object):
pass
class Derived(Super1, Super2):
pass
d = Derived()
parent_cls = some_function_to_get_defining_class(d.__class_attribute__) # <-- should return `Super1`
The __qualname__ attribute gives an indication from which class a method was inherited. However, this only returns a string, not the superclass itself. If you need to the superclass for metaprogramming, I think you are going to have to dig into the MRO.
class A:
def a(self):
return 1
def b(self):
return 2
class B:
def b(self):
return 2.5
def c(self):
return 3
class C(A,B):
pass
Using:
C.b.__qualname__
# returns:
'A.b'
However, this does not apply when using abstract methods to define an interface, since the method has to be overwritten.
from abc import abstractmethod
class A:
def a(self):
return 1
#abstractmethod
def b(self):
pass
class C(A):
def b(self):
return 100
C.b.__qualname__
# returns:
'C.b'

Get variable name from argument/parameter in class function

I try to get the name of the variable, which I passed to a function.
class A():
def __init__(self):
self.a = 1
class B():
def __init__(self):
self.b = A()
self.c = A()
def doSomething(self, hello):
print(hello)
B().doSomething(B().b)
<__main__.A object at 0x7f67571a3d68>
What I want is that I can identify in the function B().doSomething(), that the variable is b. Is this possible? One restriction is that in the function B().doSomething() only instance variables of B are passed.
For example in peewee (https://github.com/coleifer/peewee), a MySQL ORM in python, they build expressions for filtering like:
B.select().where(B.b == True)
And somehow they are able to identify, that b is passed. Because otherwise the query can not be build properly.
I know they are using static variables in the class, is this maybe the trick?
Thanks for helping! :)
Going by your B().doSomething(B().b) example call I'm going to assume you're attempting to determine if the variable hello is equivalent to the variable b declared on the class B object.
In which case, all you need to do is call the self reference. self refers to the instance of the object that you're working with and every method defined within a class automatically gets reference to the object's self as a method attribute.
Thus, to determine if the the object b variable is equal to the hello parameter all you need to do is if self.b == hello: #do code
B().b is not an instance variable of B; rather, it is an instance variable of A. In your constructor in B, you may have meant self.a to be an instance of B or self.a to be an instance of B. If this is your general idea, you can implement a boolean overloading method to destinguish between the two. In the case of your code, it may be best to create a third class, C, to check what class an attribute that is passed to doSomething belongs to:
class A():
def __init__(self):
self.a = 1
def __bool__(self):
return True
class B():
def __init__(self):
self.b = 1
def __bool__(self):
return False
class C():
def __init__(self):
self.a = A()
self.b = B()
def doSomething(self, hello):
if not hello:
print("instance of a got passed")
else:
print("instance of b got passed")
C().doSomething(C().b)
Output:
instance of b got passed

python __slots__ descriptor getter/setter

The documentation on __slots__ says they're "implemented as descriptors." Is it possible to customize the getters/setters for descriptors created via __slots__? Can I do something like
class Foo(object):
__slots__ = ['a']
def __init__(self, a):
self._a = a
#property
def a(self):
return self._a.title()
#a.setter
def a(self, x):
if len(x) == 10:
self._a = x
else:
raise ValueError('incorrect length!')
#a.deleter
def a(self):
self._a = ''
ETA: Only semi-relatedly, the self._a = a bit above would mean that the initial value of a wouldn't be run through the setter. Is there a way to pass the value into the setter on __init__ as well?
ETA2: So based on Bi Rico's answer, I worked out this:
class Foo(object):
__slots__ = ('_a',)
def __init__(self, x):
self._a = self.validate_a(x)
#staticmethod
def validate_a(x):
if x % 2 == 0:
return x
else:
raise ValueError(':(')
#property
def a(self):
return str(self._a)
#a.setter
def a(self, x):
self._a = self.validate(x)
#a.deleter
def a(self):
self._a = 0
The separate validate_a method solves my 'add-on' question about treating the value(s) passed into __init__ the same as values passed in through the setter (and as such isn't necessary if you don't want to do that.)
It feels a little hacky to only put 'dummy' var names in __slots__ (i.e., Foo._a only exists for the benefit of the Foo.a property), but it works.
Your code almost works as is; the only changes you need to make are
__slots__ = ['_a'] # _a instead of a
def __init__(self, a):
self.a = a # a instead of _a
If for some reason you really want to avoid the separate _a slot and a wrapper, you can replace the default slot descriptor with your own descriptor, but I wouldn't recommend it. Also, the replacement has to happen after the class is created:
class Foo(object):
__slots__ = ['a']
underlying_descriptor = Foo.a
#property
def a(self):
return underlying_descriptor.__get__(self, Foo).title()
#a.setter
def a(self, x):
if len(x) == 10:
underlying_descriptor.__set__(self, x)
else:
raise ValueError('incorrect length!')
#a.deleter
def a(self):
underlying_descriptor.__del__(self)
Foo.a = a
You might try to simplify all that underlying_descriptor stuff by setting Foo._a = Foo.a and accessing it through self._a, but then you have an _a attribute on your objects, and the whole point of this version is to avoid the second attribute.
You don't need to list properties in __slots__ only attributes, if you change slots to __slots__ = ['_a'], your class will work as expected.
Update
Sorry I didn't see you add-on question in my first read through. Having a static validate method is fine, but you don't need to call it explicitly in the in __init__, instead set self.a directly, only use self._a when you want to intentionally bypass the setter/getter.
I don't know what you mean by,
It feels a little hacky to only put 'dummy' var names in __slots__
a is a property of the class (which btw is also implemented using descriptors) so if you also include it in __slots__ you're instructing the class to create two conflicting descriptors for the same thing.
_a is an attribute of the class so if you're using __slots__ it must be there. Just because _a starts with an underscore doesn't make it any better or worse than any other attribute, I would call it a "protected" attribute instead of a dummy attribute :). Are you sure you want to use __slots__ at all, that seems to be the most "hacky" part of this whole thing.
Absolutely. You just reference the property and use your setter in your init. Make your class follow the same rules internally that your users are expected to follow, at least when __init__ is taking input like this.
class Foo(object):
__slots__ = ['_a']
def __init__(self, a):
self.a = a
#property
def a(self):
return self._a
#a.setter
def a(self, x):
if len(x) == 10:
self._a = x
else:
raise ValueError('incorrect length!')
#a.deleter
def a(self):
self._a = ''
This way, if someone instantiates with an "incorrect length" they'll hit the same error path as setting object values.
You absolutely don't need the static method, that's a major use case of using setters in the first place, to validate or sanitize the data before accepting it! A reason to use a method like that is if you have multiple properties that all need the same scrubbing. e.g. Foo.b, Foo.c, Foo.d all work like Foo.a. In which case, you'd also want to indicate that it's private with a leading underscore: def _validate_nums(x):
For your new code, it's exactly the same as the old, no need for a static method:
class Foo(object):
__slots__ = ('_a',)
def __init__(self, x):
self.a = x
#property
def a(self):
return str(self._a)
#a.setter
def a(self, x):
if x % 2 == 0:
self._a = x
else:
raise ValueError(':(')
#a.deleter
def a(self):
self._a = 0
A reason you might break from this is if you want an explicit undefined or default value, that your class normally prohibits (such as your original class prohibits any length that's not 10). In which case you could do:
def __init__(self, a="four"):
if a == "four":
self._a = "four"
else:
self.a = a
This example is a little weird, you'd probably use None, 0, an empty value (like [] or ()), or something else to test against elsewhere, like you do with your newer code, which doesn't need this.
It feels a little hacky to only put 'dummy' var names in slots (i.e., Foo._a only exists for the benefit of the Foo.a property), but it works.
I think you are looking at it backwards, but it makes sense since without directors we all would prefer to use Foo.a over Foo._a. However, Foo._a is your class attribute. It's what your class uses. It's the property decorators that allow Foo.a that are a little bit hacky. They are defensive measures to protect your class from misuse or bad behavior. They aren't your class attribute at all.
By also using _a instead of like internal_data you communicate to other users: _a is meant to be private, access it directly at your own risk, use the property decorators if you want expected behavior!

Global vars in python [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I currently have some class foo() with some variables that are not only shared among all instances of the foo class, but also by other classes bar.
i.e.
class foo():
__init__(self, a, b):
self.a = a
self.b = b
class bar():
__init__(self, a, b):
self.a = a
self.b = b
One solution would be to make a and b class variables, but how do I do that cleanly during construction? Could I just put both classes in the same file and have them reference some global variables a and b? Is that bad practice?
Since you did not provide your intention or real-world situation, I'll just provide some ways of sharing variable access.
1st option: global.
a=b=None
class foo():
def __init__(self, _a, _b):
global a, b
a, b = _a, _b
class bar():
def __init__(self, _a, _b):
global a, b
a, b = _a, _b
2nd option: foo's class vars
class foo():
a = b = None
def __init__(self, a, b):
foo.a, foo.b = a, b
class bar():
def __init__(self, a, b):
foo.a, foo.b = a, b
3rd option: inheritance
class foo():
def __init__(self, a, b):
self.a, self.b = a, b
class bar(foo):
pass
4th option: outer class
class outer():
a = b = None
class foo():
def __init__(self, a, b):
outer.a, outer.b = a, b
class bar():
def __init__(self, a, b):
outer.a, outer.b = a, b
5th option: compsition
class foo():
def __init__(self, a, b):
self.a, self.b = a, b
class bar():
def __init__(self, a, b):
self.foo = foo(a,b)
6th option: closure over outer-function local variables
def outer():
a = b = None
class foo():
def __init__(self, _a, _b):
nonlocal a, b
a, b = _a, _b
class bar():
def __init__(self, _a, _b):
nonlocal a, b
a, b = _a, _b
... #things with foo and bar
7th option: closure over foo's __init__ local variables.
class foo():
def __init__(self, a, b):
self.a, self.b = a, b
class bar():
nonlocal a, b
#do things with a and b directly
self.bar = bar()
You could do this:
class Foo(object):
def __init__(self, a, b):
self.a = a
self.b = b
class Bar(Foo):
pass
By inheriting from Foo, you'll be adopting Foo's construction method as well so it will act the same way. If you need to override it, you can set it up this way in Bar:
def __init__(self, a, b, c):
super(Bar, self).__init__(a, b)
self.c = c
super will call your base class' method first (in this case, Foo) and then allow you to add on if you'd like. Here's the documentation on super, if you're interested.
The usual solution is to make an object that stores the shared information, then pass that when instantiating the classes that need it. Often this is some kind of configuration information, so we'll call the class Config:
class Config(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
# default values
number = 0
text = "Nothing"
Since Python is duck-typed, any object can be used to hold this configuration; it can be an instance of a class or the class itself. The former is handy when the data is specified at runtime. The latter can be convenient since it allows the programmer to define the various bundles of attributes using inheritance at coding time. The Config class here lets you have it either way: you can instantiate it, passing keyword arguments with the shared values, or you can subclass it, providing the shared values as class attributes.
In your Foo and Bar classes you then just accept the shared data in the constructor:
# these classes both need certain pieces of data
# but are not related by inheritance
class Foo(object):
def __init__(self, shared):
self.shared = shared
class Bar(object):
def __init__(self, config):
self.config = config
And then you can either instantiate the Config class, or define a subclass, and pass the resulting object to the new objects:
# use an instance
adams_config = Config(text="Don't Panic", number=42)
foo1, bar1 = Foo(adams_config), Bar(adams_config)
# use a subclass
class LincolnConfig(Config):
number = 87
text = "Four score and seven years ago"
foo2, bar2 = Foo(LincolnConfig), Bar(LincolnConfig)
Now methods of your Foo and Bar class can get self.shared.number or self.config.text (and so on) to access the data.
Since the instances of your various classes are all holding references to the same object, a change to e.g. adams_config or LincolnConfig would be seen by any instance of any class that holds a reference to one of these objects. If this isn't the behavior you want, you could fish the data you want to "freeze" out of the config object at instantiation and set it as attributes of your instance.
You could also just use a dictionary for data you want to access in various places, but I think the benefits of inheritance and attribute-access syntax are a good argument for doing it with classes.
You could even have a global configuration object that is used as a default value so you don't need to explicitly specify it if you want things to "just work." Here we'll just use the Config class itself for that, since it already has default values for the attributes we're interested in:
class Baz(object):
def __init__(self, config=Config):
self.config = config
By using this approach instead of global variables, you make it easier for clients using your objects to have numerous instances with different settings, rather than being limited to one "bundle" of settings for all instances.
I'm not sure what you mean by "cleanly during construction"
You can use class variables by defining them outside the function like:
class A:
x = 1
def __init__(self):
pass
And just call A.x whenever you need the variable, within other classes or wherever

Categories