Let's say I've got python object A, that is an instance of class A. Every instance of class A has an attribute SubType.
I've also got classes SubType_B, SubType_C, and SubType_D, each of which has a method called ingest(). The ingest() method was previously using (self) to get all the parameters it needed, but that self is now the instance of class A.
What is the most elegant way to inherit / use the method ingest() from a SubType class (e.g. SubType_A), using the self from object A?
Previously, the ingest() method was defined in class A, but I would like to break that out into separate classes. Class A is instantiated, and based on the SubType parameter, that object would inherit the correct ingest() method from the corresponding SubType class.
In real simple terms, I'd like one object to grab a method from another object, as if it were its own.
UPDATE
Final solution was to make a factory function that returns instances of the SubType classes. This factory reads information in parameters passed to it, that determine which SubType class to instantiate. The SubType classes all extend Class A.
I had envisioned things backwards, thinking I started with the most general class, then incorporated attributes and methods from sub-classes. This factory-like-function does the requisite information gathering, then instantiates the appropriate sub-class.
Thanks to #HenryGomersall and #IgnacioVazquez-Abrams for ideas and clarification.
Related
I am learning about metaclass and I see that every class is a subclass of type class in python but sometimes I see people are using object class but object class is also a subclass of type class then what is the difference between them?
object is not a subclass of type: it is an instance of type.
object, the class, is the root of all class hierarchy in Python - however as everything in Python is an instance, it has to have a "class" that when properly instantiated with the proper parameters results in it.
As it is an obvious "chicken and egg" paradox, after all, the class type itself must inherit from object, that part of the class hierarchy is hand-wired in loop: it would be impossible to replicate the same relationships in pure Python code.
And finally: a class being an instance of a metaclass is not the same as inheriting, or being a subclass of that metaclass: inheritance hierarchy is one thing, the metaclass, which is used to construct each class itself, is another, ortogonal thing.
So, to recap: all classes in Python are themselves instances of a "metaclass" - and the default metaclass is type. All classes in Python also inherit from object - and that includes type. The class object itself must also be an instance of type, and that relationship is hardcoded in the Python runtime source-code (which is written in C in the case of cPython)
I am learning about metaclass and I see that every class is a subclass of type class in python but sometimes I see people are using object class but object class is also a subclass of type class then what is the difference between them?
object is not a subclass of type: it is an instance of type.
object, the class, is the root of all class hierarchy in Python - however as everything in Python is an instance, it has to have a "class" that when properly instantiated with the proper parameters results in it.
As it is an obvious "chicken and egg" paradox, after all, the class type itself must inherit from object, that part of the class hierarchy is hand-wired in loop: it would be impossible to replicate the same relationships in pure Python code.
And finally: a class being an instance of a metaclass is not the same as inheriting, or being a subclass of that metaclass: inheritance hierarchy is one thing, the metaclass, which is used to construct each class itself, is another, ortogonal thing.
So, to recap: all classes in Python are themselves instances of a "metaclass" - and the default metaclass is type. All classes in Python also inherit from object - and that includes type. The class object itself must also be an instance of type, and that relationship is hardcoded in the Python runtime source-code (which is written in C in the case of cPython)
Lately, I've been studying Python's class instantiation process to really understand what happen under the hood when creating a class instance. But, while playing around with test code, I came across something I don't understand.
Consider this dummy class
class Foo():
def test(self):
print("I'm using test()")
Normally, if I wanted to use Foo.test instance method, I would go and create an instance of Foo and call it explicitly like so,
foo_inst = Foo()
foo_inst.test()
>>>> I'm using test()
But, I found that calling it that way ends up with the same result,
Foo.test(Foo)
>>>> I'm using test()
Here I don't actually create an instance, but I'm still accessing Foo's instance method. Why and how is this working in the context of Python ? I mean self normally refers to the current instance of the class, but I'm not technically creating a class instance in this case.
print(Foo()) #This is a Foo object
>>>><__main__.Foo object at ...>
print(Foo) #This is not
>>>> <class '__main__.Foo'>
Props to everyone that led me there in the comments section.
The answer to this question rely on two fundamentals of Python:
Duck-typing
Everything is an object
Indeed, even if self is Python's idiom to reference the current class instance, you technically can pass whatever object you want because of how Python handle typing.
Now, the other confusion that brought me here is that I wasn't creating an object in my second example. But, the thing is, Foo is already an object internally.
This can be tested empirically like so,
print(type(Foo))
<class 'type'>
So, we now know that Foo is an instance of class type and therefore can be passed as self even though it is not an instance of itself.
Basically, if I were to manipulate self as if it was a Foo object in my test method, I would have problem when calling it like my second example.
A few notes on your question (and answer). First, everything is, really an object. Even a class is an object, so, there is the class of the class (called metaclass) which is type in this case.
Second, more relevant to your case. Methods are, more or less, class, not instance attributes. In python, when you have an object obj, instance of Class, and you access obj.x, python first looks into obj, and then into Class. That's what happens when you access a method from an instance, they are just special class attributes, so they can be access from both instance and class. And, since you are not using any instance attributes of the self that should be passed to test(self) function, the object that is passed is irrelevant.
To understand that in depth, you should read about, descriptor protocol, if you are not familiar with it. It explains a lot about how things work in python. It allows python classes and objects to be essentially dictionaries, with some special attributes (very similar to javascript objects and methods)
Regarding the class instantiation, see about __new__ and metaclasses.
I'm unclear as to what this one paragraph in the python tutorial documentation is saying.
(found here: https://docs.python.org/3/tutorial/classes.html#method-objects)
When an instance attribute is referenced that isn’t a data attribute, its class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object. When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.
From my current understanding, I think what it's saying is that whenever you reference an attribute of an instance of a class like in the 8th line of this little snippet here:
class MyClass():
attribute = "I am an attribute"
def func(self):
return "I am a function"
instance = MyClass()
print(instance.func())
When python sees
instance.func()
what it's really doing isn't looking for a method func "owned by" instance, it's looking for a function func owned by MyClass, then calling that function owned by MyClass with instance as the self parameter.
so basically it's the same thing as:
MyClass.func(instance)
I feel like I'm missing something subtle though. I don't understand what it means by
... a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object.
What is an abstract object?
What does it mean to "pack" a pointer?
What does it mean to "pack" multiple pointers?
Why even have a method object for instance if python is just going to look at MyClass's function object?
Why doesn't python just make methods be "owned by" their instances? Why even go through the whole process of calling MyClass's func instead of instance's func?
Why did the designers of the language decide to make it be this way?
"Abstract object" means that there isn't necessarily a real Python object being created, it's just a way of describing what's happening behind the scenes as if there were some object being created.
"packing" means that it's just collecting these things together into this abstract object.
So when you write
instance.func()
it internally creates something that represents the function combined with the instance. When this is called, the method function is called as you described, with the instance passed as the first argument (conventionally named self).
Why do this? So that you can pass these things around:
foo = instance.func
foo()
The value of foo contains that abstract object that represents the function combined with the instance.
Methods are owned by classes so that all instances of a class automatically get the same method. This is the essence of OO programming and the basis of inheritance among classes.
This question is related to this question about PyTables metaclasses. I was trying to subclass the IsDescription metaclass in PyTables, to define the shape of the Column by a variable:
import tables
class MyClass(tables.IsDescription):
def __init__(self, param):
var1 = tables.Float64Col(shape=(param))
MyClass1 = MyClass(12)
This throws the error: TypeError: object.__new__() takes no parameters. Using self.var1 = ... gives the same error.
In this SO question the same error is reported, and the reason is attributed to the fact that IsDescription is a metaclass.
My question (which is not answered at the linked question, and I haven't been able to find anything by Googling) is: why do metaclasses prohibit this functionality? Is it specific to this metaclass, or generic for all metaclasses?
This is generic to all metaclasses.
In fact a metaclass is instanciated when a class is being created and the parameters passed are always the same, and determine by python.
Those are :
The name of the class to create
The list of inherited classes for this class. It's a tuple of class reference. By default, for new-style class it's object
The dictionary of all fields of the class to be created
You cannot pass you parameters here as this call is done automatically by the python interpreter. In python 2, a metaclass is defined as a __metaclass__ attribute in the class itself, whereas it's a argument in the definition in the class in Python 3.
The __new__ method of the metaclass is called just before the __init__ method of your class and so, takes the same arguments as your class. You can change the behavior of your class at initialization in the metaclass rather than in the constructor for instance.
If you want to define arguments to a metaclass, you can for example use some specific fields to be defined in the class to be defined. You can also write a function that will act like a metaclass to create a class for you, and you will be able to add parameters to that function. But I don't know PyTables and your exact requirements or possibilities.