Lets say I have a library function that I cannot change that produces an object of class A, and I have created a class B that inherits from A.
What is the most straightforward way of using the library function to produce an object of class B?
edit- I was asked in a comment for more detail, so here goes:
PyTables is a package that handles hierarchical datasets in python. The bit I use most is its ability to manage data that is partially on disk. It provides an 'Array' type which only comes with extended slicing, but I need to select arbitrary rows. Numpy offers this capability - you can select by providing a boolean array of the same length as the array you are selecting from. Therefore, I wanted to subclass Array to add this new functionality.
In a more abstract sense this is a problem I have considered before. The usual solution is as has already been suggested- Have a constructor for B that takes an A and additional arguments, and then pulls out the relevant bits of A to insert into B. As it seemed like a fairly basic problem, I asked to question to see if there were any standard solutions I wasn't aware of.
This can be done if the initializer of the subclass can handle it, or you write an explicit upgrader. Here is an example:
class A(object):
def __init__(self):
self.x = 1
class B(A):
def __init__(self):
super(B, self).__init__()
self._init_B()
def _init_B(self):
self.x += 1
a = A()
b = a
b.__class__ = B
b._init_B()
assert b.x == 2
Since the library function returns an A, you can't make it return a B without changing it.
One thing you can do is write a function to take the fields of the A instance and copy them over into a new B instance:
class A: # defined by the library
def __init__(self, field):
self.field = field
class B(A): # your fancy new class
def __init__(self, field, field2):
self.field = field
self.field2 = field2 # B has some fancy extra stuff
def b_from_a(a_instance, field2):
"""Given an instance of A, return a new instance of B."""
return B(a_instance.field, field2)
a = A("spam") # this could be your A instance from the library
b = b_from_a(a, "ham") # make a new B which has the data from a
print b.field, b.field2 # prints "spam ham"
Edit: depending on your situation, composition instead of inheritance could be a good bet; that is your B class could just contain an instance of A instead of inheriting:
class B2: # doesn't have to inherit from A
def __init__(self, a, field2):
self._a = a # using composition instead
self.field2 = field2
#property
def field(self): # pass accesses to a
return self._a.field
# could provide setter, deleter, etc
a = A("spam")
b = B2(a, "ham")
print b.field, b.field2 # prints "spam ham"
you can actually change the .__class__ attribute of the object if you know what you're doing:
In [1]: class A(object):
...: def foo(self):
...: return "foo"
...:
In [2]: class B(object):
...: def foo(self):
...: return "bar"
...:
In [3]: a = A()
In [4]: a.foo()
Out[4]: 'foo'
In [5]: a.__class__
Out[5]: __main__.A
In [6]: a.__class__ = B
In [7]: a.foo()
Out[7]: 'bar'
Monkeypatch the library?
For example,
import other_library
other_library.function_or_class_to_replace = new_function
Poof, it returns whatever you want it to return.
Monkeypatch A.new to return an instance of B?
After you call obj = A(), change the result so obj.class = B?
Depending on use case, you can now hack a dataclass to arguably make the composition solution a little cleaner:
from dataclasses import dataclass, fields
#dataclass
class B:
field: int # Only adds 1 line per field instead of a whole #property method
#classmethod
def from_A(cls, a):
return cls(**{
f.name: getattr(a, f.name)
for f in fields(A)
})
Related
Say I built some classes containing some instance methods:
class A:
def func_of_A(self):
print("foo")
class B:
def func_of_B(self):
print("bar")
How can I construct an object/variable c that is an instance of both A and B, so that I can call both c.func_of_A() and c.func_of_B()?
I could of course build a new class inheriting from A and B and make c a member of that:
class C(A,B):
pass
c = C()
But that is not what I am looking for. I would rather not create a new class every time I am planning to use a combination of already built ones.
I could also create a function to dynamically define a new class and return an instance of it:
def merge(*inherit_from):
class D(*inherit_from):
pass
return D()
c = merge(A,B)
but this is beyond cursed, because now merge(A,B), merge(A) and merge(B) all return the same type <class '__main__.merge.<locals>.D'>.
There should be an intended way to do this, shouldn't?
Is there a solution that scales well with the number of classes involved? If I already have class A1, class A2, ..., class A100 and I want to construct some c to be an instance of class A2, class A23, class A72, class A99 but not the others how would I do that? Creating a new class for every combination is pretty much impossible, given the ~2^100 combinations.
You can use type() for that as #deceze mentioned
>>> class A:
... def a():
... pass
...
>>> class B:
... def b():
... pass
...
>>> def merge(name: str, *parents):
... return type(name, parents, dict())
...
>>> C = merge("C", A, B)
>>> C.a()
>>> C.b()
>>>
I am looking for best practices on setting one instance attribute that references another instance attribute after the class has been instantiated.
For example:
class Foo:
def __init__(self):
self.a = 1
self.b = self.a + 1
>>> obj_foo = Foo()
>>> obj_foo.a
1
>>> obj_foo.b
2
>>> obj_foo.a = 5
>>> obj_foo.a
5
>>> obj_foo.b
2 # I want this to be 6
Is this bad practice for one instance attribute to reference another?
I can see how implementing a method to check for and update dependent instance attributes, but this seems like a lot of overhead/hacky. Any assistance is greatly appreciated!
It seems like you don't actually want to store the value of b at all, but instead want to generate it based on the value of a dynamically. Luckily, there's a property class/decorator that you can use just for this purpose:
class Foo:
def __init__(self, a=1):
self.a = a
#property
def b(self):
return self.a + 1
This will create a read-only property b that will behave just like a normal attribute when you access it as foo.b, but will a because it is a descriptor. It will re-compute the value based on whatever foo.a is set to.
Your fears about calling a method to do the computation every time are not entirely unjustified. Using the . operator already performs some fairly expensive lookups, so your toy case is fine as shown above. But you will often run into cases that require something more than just adding 1 to the argument. In that case, you'll want to use something like caching to speed things up. For example, you could make a into a settable property. Whenever the value of a is updated, you can "invalidate" b somehow, like setting a flag, or just assigning None to the cached value. Now, your expensive computation only runs when necessary:
class Foo:
def __init__(self, a=1):
self._a = a
#property
def a(self):
return self._a
#a.setter
def a(self, value):
self._a = value
self._b = None
#property
def b(self):
if self._b is None:
# Placeholder for expensive computation here
self._b = self._a + 1
return self._b
In this example, setting self.a = a in __init__ will trigger the setter for the property foo.a, ensuring that the attribute foo._b always exists.
I am trying to dynamically create classes in Python and am relatively new to classes and class inheritance. Basically I want my final object to have different types of history depending on different needs. I have a solution but I feel there must be a better way. I dreamed up something like this.
class A:
def __init__(self):
self.history={}
def do_something():
pass
class B:
def __init__(self):
self.history=[]
def do_something_else():
pass
class C(A,B):
def __init__(self, a=False, b=False):
if a:
A.__init__(self)
elif b:
B.__init__(self)
use1 = C(a=True)
use2 = C(b=True)
You probably don't really need that, and this is probably an XY problem, but those happen regularly when you are learning a language. You should be aware that you typically don't need to build huge class hierarchies with Python like you do with some other languages. Python employs "duck typing" -- if a class has the method you want to use, just call it!
Also, by the time __init__ is called, the instance already exists. You can't (easily) change it out for a different instance at that time (though, really, anything is possible).
if you really want to be able to instantiate a class and receive what are essentially instances of completely different objects depending on what you passed to the constructor, the simple, straightforward thing to do is use a function that returns instances of different classes.
However, for completeness, you should know that classes can define a __new__ method, which gets called before __init__. This method can return an instance of the class, or an instance of a completely different class, or whatever the heck it wants. So, for example, you can do this:
class A(object):
def __init__(self):
self.history={}
def do_something(self):
print("Class A doing something", self.history)
class B(object):
def __init__(self):
self.history=[]
def do_something_else(self):
print("Class B doing something", self.history)
class C(object):
def __new__(cls, a=False, b=False):
if a:
return A()
elif b:
return B()
use1 = C(a=True)
use2 = C(b=True)
use3 = C()
use1.do_something()
use2.do_something_else()
print (use3 is None)
This works with either Python 2 or 3. With 3 it returns:
Class A doing something {}
Class B doing something []
True
I'm assuming that for some reason you can't change A and B, and you need the functionality of both.
Maybe what you need are two different classes:
class CAB(A, B):
'''uses A's __init__'''
class CBA(B, A):
'''uses B's __init__'''
use1 = CAB()
use2 = CBA()
The goal is to dynamically create a class.
I don't really recommend dynamically creating a class. You can use a function to do this, and you can easily do things like pickle the instances because they're available in the global namespace of the module:
def make_C(a=False, b=False):
if a:
return CAB()
elif b:
return CBA()
But if you insist on "dynamically creating the class"
def make_C(a=False, b=False):
if a:
return type('C', (A, B), {})()
elif b:
return type('C', (B, A), {})()
And usage either way is:
use1 = make_C(a=True)
use2 = make_C(b=True)
I was thinking about the very same thing and came up with a helper method for returning a class inheriting from the type provided as an argument.
The helper function defines and returns the class, which is inheriting from the type provided as an argument.
The solution presented itself when I was working on a named value class. I wanted a value, that could have its own name, but that could behave as a regular variable. The idea could be implemented mostly for debugging processes, I think. Here is the code:
def getValueClass(thetype):
"""Helper function for getting the `Value` class
Getting the named value class, based on `thetype`.
"""
# if thetype not in (int, float, complex): # if needed
# raise TypeError("The type is not numeric.")
class Value(thetype):
__text_signature__ = "(value, name: str = "")"
__doc__ = f"A named value of type `{thetype.__name__}`"
def __init__(self, value, name: str = ""):
"""Value(value, name) -- a named value"""
self._name = name
def __new__(cls, value, name: str = ""):
instance = super().__new__(cls, value)
return instance
def __repr__(self):
return f"{super().__repr__()}"
def __str__(self):
return f"{self._name} = {super().__str__()}"
return Value
Some examples:
IValue = getValueClass(int)
FValue = getValueClass(float)
CValue = getValueClass(complex)
iv = IValue(3, "iv")
print(f"{iv!r}")
print(iv)
print()
fv = FValue(4.5, "fv")
print(f"{fv!r}")
print(fv)
print()
cv = CValue(7 + 11j, "cv")
print(f"{cv!r}")
print(cv)
print()
print(f"{iv + fv + cv = }")
The output:
3
iv = 3
4.5
fv = 4.5
(7+11j)
cv = (7+11j)
iv + fv + cv = (14.5+11j)
When working in IDLE, the variables seem to behave as built-in types, except when printing:
>>> vi = IValue(4, "vi")
>>> vi
4
>>> print(vi)
vi = 4
>>> vf = FValue(3.5, 'vf')
>>> vf
3.5
>>> vf + vi
7.5
>>>
Let's say I have a class in Python:
class Foo(object):
a = 1
b = 2
I'd like to do some extra stuff when I access 'a' but NOT 'b'. So, for example, let's assume that the extra stuff I'd like to do is to increment the value of the attribute:
> f = Foo()
> f.a # Should output 2
> f.a # Should output 3
> f.a # Should output 4
> f.b # Should output 2, since I want the extra behavior just on 'a'
It feels like there is a way through __getattr__ or __getattribute__, but I couldn't figure that out.
The extra thing can be anything, not necessarily related to the attribute (like print 'Hello world').
Thanks.
What you are looking for is a property, which can be used nicely as a decorator:
class Foo(object):
_a = 2
#property
def a(self):
Foo._a += 1
return Foo._a - 1
b = 2
The function is called whenever you try to access foo_instance.a, and the value returned is used as the value for the attribute. You can also define a setter too, which is called with the new value when the attribute is set.
This is presuming you want the odd set-up of class attributes you only ever access from instances. (_a and b here belong to the class - that is, there is only one variable shared by all instances - as in your question). A property, however, is always instance-owned. The most likely case is you actually want:
class Foo(object):
def __init__(self):
self._a = 2
self.b = 2
#property
def a(self):
self._a += 1
return self._a - 1
Where they are instance attributes.
If you really do want the equivalent of #property for a class variable, you have to build the descriptor yourself.
You almost certainly don't want to do this—see Lattyware's answer for how to make normal instance variables, and turn one of them into a #property.
But here's how you could do it:
class IncrementOnGetDescriptor(object):
def __init__(self, initval=None):
self.val = initval
def __get__(self, obj, objtype):
self.val += 1
return self.val - 1
def __set__(self, obj, val):
self.val = val
class Foo(object):
a = IncrementOnGetDescriptor(2)
b = 2
Now you can test it:
>>> f = Foo()
>>> f.a
2
>>> Foo.a
3
>>>> f.a
4
Turning this into a #classproperty decorator is left as an exercise for the reader.
PS, this still isn't exactly like a normal class variable. Setting Foo.a = 10 will replace your magic auto-incrementing value with a normal 10, while setting foo.a = 10 will update the class with an auto-incrementing 10 instead of storing an instance variable in f. (I originally had the __set__ method raise AttributeError, because normally you'd want an auto-incrementing magic variable be read-only, but I decided to show the more complex version just to show all the issues you have to deal with.)
I have a class A and i want a class B with exactly the same capabilities.
I cannot or do not want to inherit from B, such as doing class B(A):pass
Still i want B to be identical to A, yet have a different i: id(A) != id(B)
Watch out, i am not talking about instances but classes to be cloned.
I'm pretty sure whatever you are trying to do can be solved in a better way, but here is something that gives you a clone of the class with a new id:
def c():
class Clone(object):
pass
return Clone
c1 = c()
c2 = c()
print id(c1)
print id(c2)
gives:
4303713312
4303831072
I guess this is not what you wanted but its what the question seems to be asking for...
class Foo(object):
def bar(self):
return "BAR!"
cls = type("Bar", (object,), dict(Foo.__dict__))
print cls
x = cls()
print x.bar()
maybe i misunderstood you question but what about wrapping A in B?
class A:
def foo(self):
print "A.foo"
class B:
def __init__(self):
self._i = A()
def __getattr__(self, n):
return getattr(self._i, n)
You can clone the class via inheritance. Otherwise you are just passing around a reference to the class itself (rather than a reference to an instance of the class). Why would you want to duplicate the class anyway? It's obvious why you would want to create multiple instances of the class, but I can't fathom why you would want a duplicate class. Also, you could simply copy and paste with a new class name...