I am new in Python classes and trying to write an interface for a scientific code via Tkinter. But I can not call a function (which is in another class and opens a different frame) from a class or function. I have been searching for more than 2 days but could not find an answer to my case. If you explain like explaining a child I would be very happy since I don't know much technical details.
My code structure is like:
class first_class(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
....
def WhateverFunction():
"do sth"
class second_class(tk.Tk):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
.....
**I want to use "WhateverFunction" here**
.....
so basically, I can not access that function from another class.
The searches I found online like Python using methods from other classes method. Bu This did not solve my problem. It is maybe because I am working with different Tkinter frames. I do not now... Thanks already, cheers!
In your code you defined the function WhateverFunction as a local function within __init__. So it can't be seen from other sections of your code and it's impossible to be called.
Instead you can implement your function as a method, for example. It would look like this:
class first_class(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
....
def WhateverFunction(self):
"do sth"
Now the function can be called everywhere as a method of an instance of first_class:
first_class_instance = first_class()
first_class_instance.WhateverFunction()
I asked the exact same question on here a while back with no response. Basically, you can't do it. WhateverFunction only exists within the scope of __init__, which itself can only be called from second_class. This is done with the method described in the 'using methods from other classes' question you linked to, but it is useless for doing what you want to do because you may only get an output from __init__, and hence you can't access any functions defined within that function.
To work around this, why not define WhateverFunction globally and then call it as usual, or declare it outside of the __init__ function but still within first_class?
Just create an instance of that class, and call the method if the second_class instance should be composed of the first one.
def second_class(tk.Tk):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
first_object = first_class().WhateverFunction()
Now a better approach would be to inherit second_class from the first one instead, and calling the method considering both classes have same parent, provided inheritance makes sense.
def second_class(first_class):
def __init__(self, parent, controller):
super(second_class, self).__init__(parent, controller)
self.WhateverFunction()
Note:- please try to follow certain conventions of Python like naming classes with camel case, and methods/functions with snake case.
Related
I have an existing class TSEparser that inherits from a parent class Subparser, but now I want to add another parent class (SubparserMixin) to class TSEparser. However, the problem is that the arguments passed by the initial inheritance gets in the way of this new inheritance- how can I fix this?
i.e:
class Subparser:
def __init__(self, filename, data_group, **kwargs):
self.data_group = data_group
self.filename = filename
self.__dict__.update(kwargs)
class TSEparser(Subparser):
def __init__(self, filename, data_group, **kwargs):
super().__init__(filename, data_group, **kwargs)
Now I want to add another parent class SubparserMixin so we have class TSEparser(Subparser, SubparserMixin), however Subparsermixin looks like this:
class SubparserMixin:
def __init__(self):
self.subparsers = {}
self.context = PacketContext
Is there some way I can inherit separately from both Parent Classes? Something like this:
class TSEparser(Subparser):
def __init__(self, filename, data_group, **kwargs):
super(Subparser).__init__(filename, data_group, **kwargs)
super(SubparserMixin).__init__()
I know the syntax is not correct but I hope it is clear what I am trying to do!
You can specify which class' constructor gets called by simply using its name. So in your example you can just do
class TSEparser(Subparser, SubparserMixin):
def __init__(self, filename, data_group, **kwargs):
Subparser.__init__(self, filename, data_group, **kwargs)
SubparserMixin.__init__(self)
There is no good and easy way to make this work using super. You can check out this question for more detail. super normally takes care of calling the proper classes for you. If you want to call the __init__ of a specific class manually (e.g. because the required arguments are different), you need to call it directly using its name as shown above.
Edit: My code example mistakenly didn't pass self when calling the base __init__ methods. Note that this is a difference between calling by super and directly by base class. super doesn't require self, while direct calling does.
# without self
super().__init__()
# with self
Base.__init__(self)
So, I am programming my Python Program with the MVC-Architecture, and I want everything nice and seperated from each other. I don't want the View of my GUI having to work with the Controllers instance and so on. So I made an 'IController' abstract class which is the parent of 'Controller', which has all of the functions. In 'IController' I have the functions my Model and View need to access. The Controller looks somewhat like this:
class IController:
def method(self):
pass
class Controller(IController):
self.x = 'Hello'
def method(self):
print('self.x)
So where I previously had
class Frame(tk.Frame):
def __init__ (self, controller):
self.controller = controller
button = tk.Button(self, command=lambda: self.controller.method()
I now want to turn this into
class Frame(tk.Frame):
def __init__ (self, controller):
self._controller = type(controller)
button = tk.Button(self, command=lambda: self._controller.method()
The problem here is, that when I do this, I can't keep the instance of my 'Controller' Class. I need this, since the instance has values and methods I need to work with here. I also can't save the instance of 'Controlle'r in 'IController' since it is an abstract class, so I won't instance it and can't save anything in it.
I expected it to just work, but I am not sure if this is possible now. I read that casting is not possible in python, but I think there must be another way for me to fix this. When I ran it, it told me that I am lacking 'self'. I can't send the instance of the Controller with it, then it would not be capsulated. Is there a way around this?
For other people who might try the same: It is not possible to do this like you would do it in C# or others. I solved it by re-writing my program in and learning C#. That and some ugly workarounds are the only possibilities.
I have a class Document, this class is really complex to instantiate so I have a builder object to create them. Both elements are not mine, so I can't change them
Now, I want to create a subclass of Document, just to add some specific methods. In order to keep using the provided builder I tried this:
class SpecialDocument(Document):
def __new__(cls, *args):
return DocumentBuilder(*args)
def __init__(self, *args, **kwargs):
#My initialization
The problem here is that the __init__ method never executes cause the __new__ method doesn't return a SpecialDocument (It returns a Document)
In my particular case I don't need to build my SpecialDocument differently from how I build a Document. Is there a way to use the same builder? If not, how can I achieve this? I just want to inherit from Document to add particular functionalities, maybe it could be achieved with metaclasses but I never used them (Probably cause I don't fully understand it), a little insight on them would be nice if it can help solving my problem
You don't actually need a metaclass here - you just have to proper call the superclass' __new__ method. The way you are doing it, the instantiation of the superclass does not "know" it is being called from a subclass at all.
So, just write your code like this instead:
class SpecialDocument(Document):
def __new__(cls, *args):
return super().__new__(cls, *args)
def __init__(self, *args, **kwargs):
#My initialization
Now, that is the ordinary way to do it - and would work if the code in your "builder" function was correctly placed inside Docment's __new__ or __init__.
Since the code there does nt do that, and you can[ t pass your subclass as a parameter to the builder, a working solution might be to create a normal document, and swap its class after it has been built:
def special_document_init(special_document):
...
class SpecialDocument(Document):
def my_special_method(self, ...):
...
def overriden_method(self):
...
result = super().overriden_method()
...
def build_special_document(*args):
document = DocumentBuilder(*args)
document.__class__ = SpecialDocument
special_document_init(document)
return document
I am new to Python. I came across Python code in an OpenFlow controller that I am working on.
class SimpleSwitch(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(SimpleSwitch, self).__init__(*args, **kwargs)
self.mac_to_port = {}
My questions are as follows.
Is __init__ the constructor for a class?
Is self the same as C++'s this pointer?
Does super(SimpleSwitch, self).__init__(*args, **kwargs) mean calling constructor for parent/super class?
Can you add a new member to self as mac_to_port? Or has that been already added and just being initialized here?
__init__ is the initialiser; __new__ is the constructor. See e.g. this question.
Effectively yes: the first argument to instance methods in Python, called self by convention, is the instance itself.
Calling the parent class's initialiser, yes.
It's adding a new attribute to SimpleSwitch in addition to what the parent class already has, an empty dictionary.
Super in Python is not like C++'s super. I have not used C++, but I can tell you that super in python does not act the same. Instead of calling the parent, python super calls the children of the class in which super is called, then moves in an interesting chain. Think of three tiered class system where there is a single base class, two subclasses to that base class, and two subclasses to those subclasses. Calling super on the bottom tier would call the parent immediately above it, but calling super in one of the second-tier classes would call their children first, then it looks to the side and calls the other classes on it's own tier, then the children of that same-tier class are called. Once all of the same-tier classes and all of their children re called, then super calls the parent of the middle-tier classes.
It's hard to explain in words. Watch Raymond Hettinger's "super considered super" talk from PyCon. He gives a very good explanation of how it works, and why python's super should not be called 'super'.
What if anything is the important difference between the following uses of calling the superclass initiation function?
class Child_1(Parent):
def __init__(self):
super(Child, self).__init__()
class Child_2(Parent):
def __init__(self):
super(Parent, self).__init__()
class Child_3(Parent):
def __init__(self):
Parent.__init__(self)
The first form (though you'd fix the typo and make it Child_1 in the call to super) would be what you'd generally want. This will look up the correct method in the inheritence hierarchy.
For the second form, you're looking for parents classes of Parent that implement this method, and you'd have to have a very special use case (if you want to skip a parent, don't derive from them) in order to want to do that.
The third in many cases would wind up doing the same as the first, though without seeing the code for Parent, it's hard to be sure. The advantage of the first method over the third is that you can change the base class of the child and the right method will still be called.
Also, the first form allows for cooperative multiple inheritence. See this post or this writeup to understand the cases where this would be useful or necessary.