I'm creating a subclass for the wx.TextCtrl in wxpython.
I want this class to add extra data to the wx.TextCtrl widgets similar as to the way extra data can be added to a ComboBox or ListBox.
Here's my code:
import wx
class ExtraDataForTxtCtrl(wx.TextCtrl):
def __init(self, ExtraTextData):
self.ExtraTextData=ExtraTextData
def getExtraTCData(self):
return self.ExtraTextData
def setExtraTCData(self, ExtraTextData):
self.ExtraTextData=ExtraTextData
My problem is that I'm new to python and have no idea how to implement this and if it is correct or not.
import wx
class ExtraDataForTxtCtrl(wx.TextCtrl):
def __init__(self,*args,**kwargs):
self.ExtraTextData=kwargs.pop("ExtraTextData")
wx.TextCtrl.__init__(self,*args,**kwargs)
def getExtraTCData(self):
return self.ExtraTextData
def setExtraTCData(self, ExtraTextData):
self.ExtraTextData=ExtraTextData
possibly a better solution would be to use set/getattr
class DataTxtCtrl(wx.TextCtrl):
def __init__(self,*args,**kwargs):
self.datadict = {}
self.ExtraTextData=kwargs.pop("ExtraTextData")
wx.TextCtrl.__init__(self,*args,**kwargs)
def __getattr__(self,attr):
return self.datadict[attr]
def __setattr__(self,attr,val):
self.datadict[attr]=val
then you can set many variables and use it like normal
a = wx.App(redirect=False)
f = wx.Dialog(None,-1,"Example")
te = DataTxtCtrl(f,-1,"some_default")
te.somevar = "hello"
te.someother = "world"
print te.somevar+" "+te.someothervar
f.ShowModal()
Instead of creating a subclass I just decided to create my own class which links an extra string value to wx.textCtrl widgets.
Thanks to all who contributed! :)
Heres my code:
class TextDataHolder:
def __init__(self, wxTextControl, data):
self.wxTextControl=wxTextControl
self.data=data
def setDataTxt(self,data):
self.wxTextControl=wxTextControl
self.data=data
def getDataTxt(self):
return self.data
Heres how I implemented it:
import wx, TextDataHolder
exampleCtrl=wx.TextCtrl(self, -1, "Hello")
exampleData=TextDataHolder.TextDataHolder(exampleCtrl,"Sup?")
print exampleData.getDataTxt() #prints 'Sup?'
Related
Say I have 2 different implementations of a class
class ParentA:
def initialize(self):
pass
def some_event(self):
pass
def order(self, value):
# handle order in some way for Parent A
class ParentB:
def initialize(self):
pass
def some_event(self):
pass
def order(self, value):
# handle order in another for Parent B
How can I dynamically let some 3rd class inherit from either ParentA or ParentB based on something like this?
class MyCode:
def initialize(self):
self.initial_value = 1
def some_event(self):
# handle event
order(self.initial_value)
# let MyCode inherit from ParentA and run
run(my_code, ParentA)
Simply store the class-object in a variable (in the example below, it is named base), and use the variable in the base-class-spec of your class statement.
def get_my_code(base):
class MyCode(base):
def initialize(self):
...
return MyCode
my_code = get_my_code(ParentA)
Also, you can use type builtin. As callable, it takes arguments: name, bases, dct (in its simplest form).
def initialize(self):
self.initial_value = 1
def some_event(self):
# handle event
order(self.initial_value)
subclass_body_dict = {
"initialize": initialize,
"some_event": some_event
}
base_class = ParentA # or ParentB, as you wish
MyCode = type("MyCode", (base_class, ), subclass_body_dict)
This is more explicit than snx2 solution, but still - I like his way better.
PS. of course, you dont have to store base_class, nor subclass_body_dict, you can build those values in type() call like:
MyCode = type("MyCode", (ParentA, ), {
"initialize": initialize,
"some_event": some_event
})
Just as a quick copy-and-paste-ready snippet, I've added the comments from shx2's answer to create this (memoized with a created_classes dict attribute, so that the classes created by successive identical calls with the same class will give identical classes):
class ParentA:
val = "ParentA"
class ParentB:
val = "ParentB"
class DynamicClassCreator():
def __init__(self):
self.created_classes = {}
def __call__(self, *bases):
rep = ",".join([i.__name__ for i in bases])
if rep in self.created_classes:
return self.created_classes[rep]
class MyCode(*bases):
pass
self.created_classes[rep] = MyCode
return MyCode
creator = DynamicClassCreator()
instance1 = creator(ParentA, ParentB)()
print(instance1.val) #prints "ParentA"
instance2 = creator(ParentB, ParentA)()
print(instance2.val) #prints "ParentB"
If you wanted to get fancy you could even make DynamicClassCreator a Singleton: https://stackoverflow.com/a/7346105/5122790
As an alternative to Chris's answer implementing the memoisation suggestion for shx2's answer, I'd prefer to use a memoize decorator (the end result is still a class but it's clearer to me that the function is the interface), and also use setdefault to simplify adding to the memo dict, and do not convert the names to string but use the tuple bases itself as the key, simplifying the code to:
class Memoize:
def __init__(self, f):
self.f = f
self.memo = {}
def __call__(self, *args):
return self.memo.setdefault(args, self.f(*args))
class ParentA:
def initialize(self):
pass
class ParentB:
def initialize(self):
pass
#Memoize
def get_my_code(base):
class MyCode(base):
def initialize(self):
pass
return MyCode
a1 = get_my_code(ParentA)
a2 = get_my_code(ParentA)
b1 = get_my_code(ParentB)
print(a1 is a2) # True
print(a1 is b1) # False
(Not a good example as the code provided doesn't actually do anything other than overwrite the parent class's initialize method...)
I have an issue with sharing data between classes. I guess how it works with objects, but I need to share data without creating objects, for example:
class First_class:
def __init__(self):
var = 1 ##create some random variable
class Second_class:
def on_click(self):
print(var) ##working with variable from First_class
First_class()
Second_class()
Some ideas on how to make it or some better solution? btw I use Tkinter and these classes simulate frames with some widgets, so more specifics:
class Frame1:
def __init__(self):
name = Enter(root)
class Frame2:
def on_click(self):
print(name.get())
Frame1()
Frame2()
Set the variable as a class property instead of under init, as the class would have to be initialised in order to get that value.
class First_class:
var = 1
def __init__(self):
pass
class Second_class:
def on_click(self):
print(First_class.var)
I have a python plugin where the main.py file displays a QTextBrowser and writes some text. This works fine.
I wrote a second file anotherFile.py which identifies the same QTextBrowser but cannot write any text to it. Perhaps it needs to take ownership, I'm not sure?
Here is the code used:
# main.py #
from Example_dockwidget import ExampleDockWidget
from anotherFile import anotherClass
class Example:
def __init__(self, iface):
self.iface = iface
def function(self):
self.dockwidget = ExampleDockWidget()
self.dockwidget.show()
textBrowser = self.dockwidget.textBrowser
#textBrowser.setText('This works!')
a = anotherClass(self)
a.anotherFunction()
# anotherFile.py #
from Example_dockwidget import ExampleDockWidget
class anotherClass:
def __init__(self, iface):
self.iface = iface
self.dockwidget = ExampleDockWidget()
def anotherFunction(self):
textBrowser = self.dockwidget.textBrowser
textBrowser.setText('This does not work!')
print 'Why?'
# Example_dockwidget.py #
FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'Example_dockwidget_base.ui'))
class ExampleDockWidget(QtGui.QDockWidget, FORM_CLASS):
def __init__(self, parent=None):
super(ExampleDockWidget, self).__init__(parent)
self.setupUi(self)
Your two classes both create their own ExampleDockWidget. Only one of them is shown (has its show method called) but there are two.
So it's not surprising that text sent to one does not appear on the other. You need to arrange for your anotherClass object to obtain a reference to the other ExampleDockWidget so it can share the same one.
As strubbly mentioned, I need to reference the same ExampleDockWidget instead of creating separate versions. In the anotherFile.py file, I added an extra parameter to take in ExampleDockWidget:
class anotherClass:
def __init__(self, iface, dockwidget):
self.iface = iface
self.dockwidget = dockwidget
def anotherFunction(self):
textBrowser = self.dockwidget.textBrowser
textBrowser.setText('This does not work!')
print 'Why?'
And then inserted the reference in the main.py file:
def function(self):
self.dockwidget = ExampleDockWidget()
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget)
self.dockwidget.show()
textBrowser = self.dockwidget.textBrowser
#textBrowser.setText('This works!')
a = anotherClass(self.iface, self.dockwidget)
a.anotherFunction()
I'm not understanding any online documentation about how to make inheritance work.
I have this here:
import maya.cmds as cmds
class RigLegs():
def __init__(self, *args):
self.rigLegs()
def rigLegs(self):
self.items["side"] = "left"
self.lIK = cmds.duplicate(self.lJoints["hip"], n = self.getName("hip_IK"))
for i in self.lIK:
newName = i[0].replace("_JNT", "_IK")
cmds.rename(i, newName)
But it's complaining that there is no self.items - I have to inherit it from another class which is far too large to post here. Can anyone help me figure out how to do that? I've researched online and nothing makes any sense.
The other class is in a different file altogether.
To inherit from another class do:
class RigLegs(base_class_name):
An Example:
class base_class():
items = [1,2,3]
class pie(base_class):
def __init__(self):
print (self.items)
instance = pie()
You can read more in the Python Documentation
With imports:
file (apples.py)
class base():
items = [1,3,4]
file (main_file.py)
import apples
class pie(apples.base):
def __init__(self):
self.pies()
def pies(self):
print(self.items)
instance = pie()
In the class declaration: class RigLegs(), you should include all the classes you want to inherit from, such as in:
class RigLegs(Ancestor1, Ancestor2):
# Your code chere.
Don't forget that you still need to call the initialization logic of your ancestors.
def __init__(self):
super(RigLegs, self).__init__()
I have a model where I want to use a class method to set the default of for a property:
class Organisation(db.Model):
name=db.StringProperty()
code=db.StringProperty(default=generate_code())
#classmethod
def generate_code(cls):
import random
codeChars='ABCDEF0123456789'
while True: # Make sure code is unique
code=random.choice(codeChars)+random.choice(codeChars)+\
random.choice(codeChars)+random.choice(codeChars)
if not cls.all().filter('code = ',code).get(keys_only=True):
return code
But I get a NameError:
NameError: name 'generate_code' is not defined
How can I access generate_code()?
As I said in a comment, I would use a classmethod to act as a factory and always create you entity through there. It keeps things simpler and no nasty hooks to get the behaviour you want.
Here is a quick example.
class Organisation(db.Model):
name=db.StringProperty()
code=db.StringProperty()
#classmethod
def generate_code(cls):
import random
codeChars='ABCDEF0123456789'
while True: # Make sure code is unique
code=random.choice(codeChars)+random.choice(codeChars)+\
random.choice(codeChars)+random.choice(codeChars)
if not cls.all().filter('code = ',code).get(keys_only=True):
return code
#classmethod
def make_organisation(cls,*args,**kwargs):
new_org = cls(*args,**kwargs)
new_org.code = cls.generate_code()
return new_org
import random
class Test(object):
def __new__(cls):
cls.my_attr = cls.get_code()
return super(Test, cls).__new__(cls)
#classmethod
def get_code(cls):
return random.randrange(10)
t = Test()
print t.my_attr
You need specify the class name: Organisation.generate_code()