I have two classes with a common function f, like here:
class ClassA(object):
def f(self, var):
self.A = g(var, self.A)
# specific code for ClassA, also changing self.A
class ClassB(object):
def f(self, var):
self.B = g(var, self.B)
# specific code for ClassB, also changing self.B
In both classes, f does the same on two variables called A and B, which are structurally equivalent. I would like to put f it into an abstract class to avoid code duplication. One way to do this is
class ClassX(object):
def f(self, var):
self.X = g(var, self.X)
class ClassA(ClassX):
# specific code for ClassA, also changing self.X
class ClassB(ClassX):
# specific code for ClassB, also changing self.X
In this solution the variables A and B have been renamed X. However, to make my code more self-explaining, I would like to keep those specific names (say A,B) for X in the special classes.
Is there a way to do this?
Also please comment if you can suggest a more meaningful and descriptive title, so it becomes more valuable to the community.
Edit: The solution should also work if the variables A, B take a type which is pass-by-value and should assume that both their value and type might be changed from outside the class during the program execution.
First, a caveat: if your case actually calls for inheritance of the kind you describe, then the variable name should probably be the same. In most cases, giving different names to attributes that are identical in two related classes doesn't make code more self-explaining -- it makes it less self-explaining. It makes the attributes look different when they're really the same, adding complexity and potential for confusion.
However, I can imagine a few cases where you might want to do something like this -- it sounds a bit like you want to define a common interface to two different kinds of objects. One simple approach would be to use properties to define aliases; so in each class, you'd have different attributes (A and B), but you'd also define a property, X, that would access the appropriate attribute in either case. So in ClassA, you'd do something like this in the class definition:
#property
def X(self):
return self.A
#x.setter
def X(self, value):
self.A = value
#x.deleter
def X(self):
del self.A
And in ClassB:
#property
def X(self):
return self.B
#x.setter
def X(self, value):
self.B = value
#x.deleter
def X(self):
del self.B
Then, you could define a common function that would work only with X, which subclasses could inherit, overriding property X in whatever way is appropriate.
This is rarely worth the additional layer of indirection though. Most of the time, if there's a good reason for two classes to share a method, then they should also share the attributes that the method changes, name and all.
If all you want to do is alias an instance attribute, you could just use a property.
class A(object):
def f(self, var):
self.x = g(var, self.x)
#property
def x(self):
return getattr(self, self.x_alias)
#x.setter
def x(self, val):
setattr(self, self.x_alias, val)
class AA(A):
x_alias = 'aval'
def __init__(self, aval):
self.aval = aval
class AB(A):
x_alias = 'bval'
def __init__(self, bval):
self.bval = bval
Related
I have a custom class whose instances are initialized with several attributes foo, bar, ... that are numeric values or strings. These attributes are used by several class methods to calculate additional attributes of the class instance. I would like to define these attributes as properties, so that when changing them, the additional attributes are recalculated. The following works:
class MyClass:
def __init__(self,foo,bar):
self._foo = foo
self._bar = bar
#property
def foo(self):
return self._foo
#foo.setter
def foo(self,new_foo):
old_foo = self._foo:
self._foo = new_foo
if old_foo != new_foo:
self._force_recalc()
#property
def bar(self):
return self._bar
#bar.setter
def bar(self,new_bar):
old_bar = self._bar:
self._bar = new_bar
if old_bar != new_bar:
self._force_recalc()
def _force_recalc(self)
# call some methods that recalculate attributes
However, two aspects strike me as inelegant:
The setter methods are basically copy-paste with only the variable names adjusted. But I couldn't come up with a solution that makes use of a common setter method.
Is there a way to avoid old_foo and old_bar? They result from the fact that _force_recalc must be called after foo and bar were reset, but only if their value changed.
I first tried the solution suggested by #Barmar. This works, but lead to the problem of an unnecessary amount of recalculations during initialization of all the properties. Addtionally, they still had to be defined individually and I was unable to check whether the value actually changed.
Following #juanpa.arrivillaga's advice, I defined my own decorator class and ended up with something like this:
class MyClass:
class _MyProperty:
def __init__(self, value=None):
self.value = value
def __get__(self, instance, owner=None):
return self.value
def __set__(self, instance, value):
if value != self.value:
self.value = value
instance._force_recalc()
#classmethod
def _set_init_state(cls,values):
cls.foo,cls.bar = [cls._MyProperty(value) for value in values]
def __init__(self,foo,bar):
self._set_init_state((foo,bar))
self._force_recalc()
def _force_recalc(self)
# call some methods that recalculate attributes
While this definitely looks less repetitive, it can probably be argued that the former was more explicit. However, I like it and it solves my original request.
I've searched for this for a few hours today but didn't get a recent and satisfactorily definitive answer.
Suppose we have two particular classes that have both overlapping method names and specific individual methods. Getting rid of the unnecessary parts let's work with the following classes.
class A():
def __init__(self, a_arg1, a_arg2):
self.a_arg1 = a_arg1
self.a_arg2 = a_arg2
#property
def gimme_1(self):
return self.a_arg1
#property
def gimme_2(self):
return self.a_arg2
#property
def prop(self):
return 'A'
and also
class B():
def __init__(self, b_arg1, b_arg2, b_arg3):
self.b_arg1 = b_arg1
self.b_arg2 = b_arg2
self.b_arg3 = b_arg3
#property
def give_1(self):
return self.b_arg1
#property
def give_2(self):
return self.b_arg2
#property
def give_3(self):
return self.b_arg3
#property
def prop(self):
return 'B'
My goal is to make a third class that can morph into one of these, namely, it will have all the methods that these two have and act as if it is one of them whichever is requested. That's the motivation for the title of the question.
class C(A, B):
def __init__(self, some_list):
self.some_list = some_list
#property
def gimme_1(self):
return self.some_list[0]
#property
def gimme_2(self):
return self.some_list[1]
#property
def give_1(self):
return self.some_list[0] ** 2
#property
def give_2(self):
return self.some_list[1] ** 2
#property
def give_3(self):
return self.some_list[2]
#property
def prop(self):
return 'C'
Concrete questions:
Do we have to initialize the parents for this particular instance? If yes how should the super() be used.
This would really help me getting away with isinstance(x, A) or isinstance(x, B) type of querying. Is there any best practice that discourages such usage? Notice that the Pythonic duck typing is really not so relevant for me in my case. There are a lot of branching necessarily happening for different computational algorithms. Hence I'm really using classes as data-bundling containers but not using them as state recorders. In other words, there is hardly ever change in their instance data. But their data is used in different branches depending on which class they are. Therefore getting the right kind of object is essential for me.
Instead of rewriting the methods, why not take advantage of the benefits of inheritance? Let the parent __init__s take care of setting up instance values, and let them provide the method implementations.
class C(A, B):
def __init__(self, arg1, arg2, arg3):
A.__init__(self, arg1, arg2)
B.__init__(self, arg1**2, arg2**2, arg3)
#property
def prop(self):
return 'C'
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!
Is it possible in Python to get the name of property currently being accessed, modified for deleted inside the function? For example, I've got this code with some pseudo-code inside:
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
prop = get_current_property() #prop is set to 'x'
return self._x
#x.setter
def x(self):
"""I'm the 'x' property."""
prop = get_current_property() #prop is set to 'x'
return self._x
#property
def y(self):
"""I'm the 'x' property."""
prop = get_current_property() #prop is set to 'y'
return self._x
So the pseudo-code here is the get_current_property(), which should work inside of the getter, setter and deleter methods for each property. Any way to do this?
So, there is no way to make it easy and sexy. Only dirty-inspecty magic, my friend.
import inspect
class A(object):
#property
def b(self):
print inspect.stack()[0][3]
A().b
will give you result you want, but you should do it only if there is no way you can deal with your things.
Btw, you can try to make a decorator, which will take a function, take its __name__ and send it as argument.
Here is implementation of idea:
def named_property(func):
return property(lambda *a, **kwa: func(*a, fname=func.__name__, **kwa))
class A(object):
#named_property
def b(self, fname):
print fname
A().b # will print 'b'
As #Martijn Pieters said, there is no straightforward way for the method to get a reference to itself.
I'm trying to understand why the property definition (written by you) wouldn't already know its own name. I'm guessing that you want to do this so that you can create a bunch of properties programmatically without a separate explicit defitinition for each one.
Try something like this to build a new class dynamically while creating some of its properties from a list:
def make_getter_setter(name):
# this function uses an implicit closure to "freeze" the local value of name
# within the scope of the getter/setter functions
def getter(self):
return name
def setter(self):
pass # your original code doesn't make clear that the setter should actually do anything
return getter, setter
class C(object):
def __init__(self):
# dictionary to store the values of the properties
# this doesn't do anything now, but I presume you'll want to allow
# setting the properties later, and you'll need somewhere to store
# their values
self._properties = {}
for name in ('spam', 'eggs', 'ham'):
getter, setter = make_getter_setter(name)
setattr(C, name, property(getter, setter, doc="I'm the '%s' property" % name))
foo = C()
print foo.eggs, foo.ham # shows their values
help(foo) # shows their doc strings
Is it possible, when instantiating an object, to pass-in a class which the object should derive from?
For instance:
class Red(object):
def x(self):
print '#F00'
class Blue(object):
def x(self):
print '#00F'
class Circle(object):
def __init__(self, parent):
# here, we set Bar's parent to `parent`
self.x()
class Square(object):
def __init__(self, parent):
# here, we set Bar's parent to `parent`
self.x()
self.sides = 4
red_circle = Circle(parent=Red)
blue_circle = Circle(parent=Blue)
blue_square = Square(parent=Blue)
Which would have similar effects as:
class Circle(Red):
def __init__(self):
self.x()
without, however, affecting other instances of Circle.
Perhaps what you are looking for is a class factory:
#!/usr/bin/env python
class Foo(object):
def x(self):
print('y')
def Bar(parent=Foo):
class Adoptee(parent):
def __init__(self):
self.x()
return Adoptee()
obj=Bar(parent=Foo)
I agree with #AntsAasma. You should probably consider using dependency injection. Atleast in the example given (which I'm sure is greatly simplified to illustrate your problem), the color of a shape is better represented by via a has-a relationship rather than with a is-a relationship.
You could implement this via passing in the desired color object to the constructor, storing a reference to it, and delegating the function call to this object. This greatly simplifies the implementation while still retaining the desired behavior. See an example here:
class Red(object):
def x(self):
print '#F00'
class Blue(object):
def x(self):
print '#00F'
class Shape(object):
def __init__(self,color):
self._color=color
def x(self):
return self._color.x()
class Circle(Shape):
def __init__(self, color):
Shape.__init__(self,color)
self.x()
class Square(Shape):
def __init__(self, color):
Shape.__init__(self,color)
self.x()
self.sides = 4
red_circle = Circle(color=Red())
blue_circle = Circle(color=Blue())
blue_square = Square(color=Blue())
Edit: Fixed names of constructor arguments in sample code
It sounds like you are trying to use inheritance for something that it isn't meant for. If you would explain why you want to do this, maybe a more idiomatic and robust way to achieve your goals can be found.
If you really need it, then you could use type constructor, e.g. within a factory function (or inside __new__ method, but this is probably safer approach):
class Foo(object):
def x(self):
print 'y'
class Bar(object):
def __init__(self):
self.x()
def magic(cls, parent, *args, **kwargs):
new = type(cls.__name__, (parent,), cls.__dict__.copy())
return new(*args, **kwargs)
obj = magic(Bar, parent = Foo)
As everybody else says, that's a pretty weird usage, but, if you really want it, it's surely feasible (except for the mysterious Bar that you pull out of thin air in comments;-). For example:
class Circle(object):
def __init__(self, parent):
self.__class__ = type('Circle', (self.__class__, parent), {})
self.x()
This gives each instance of Circle its own personal class (all named Circle, but all different) -- this part is actually the key reason this idiom is sometimes very useful (when you want a "per-instance customized special method" with new-style classes: since the special method always gets looked up on the class, to customize it per-instance you need each instance to have a distinct class!-). If you'd rather do as much class-sharing as feasible you may want a little memoizing factory function to help:
_memo = {}
def classFor(*bases):
if bases in _memo: return _memo[bases]
name = '_'.join(c.__name__ for c in bases)
c = _memo[bases] = type(name, bases, {})
return c
(here I'm also using a different approach to the resulting class's name, using class names such as Circle_Red and Circle_Blue for your examples rather than just Circle). Then:
class Circle(object):
def __init__(self, parent):
self.__class__ = classFor(Circle, parent)
self.x()
So the technique is smooth and robust, but I still don't see it as a good match to the use case you exemplify with. However, it might be useful in other use cases, so I'm showing it.