The first attempt at wxPython was a good experience. However I don’t like putting a pile of code in a class’s init method, and the examples show drawing up the whole UI in the init. When I tried to refactor I came unstuck. Time to learn a little bit of Python theory.
Python Class.Self
Python classes work slightly different from most classes. There is a concept of self, which needs to be passed into methods, but you cannot put it into a call. Which is confusing to a purist from the C languages.
For example, in my class I have a method called generateId, which takes the duck species and adds a number.
def generateId(self, species):
newId = species + "12345"
return newId
You would expect to call this by calling:
generateId(self, "Mallard)
But the word ‘self’ while totally required in the method signature, is not allowed in the call. The correct call is:
self.generateId(species)
The ‘self’ word is the glue that makes it work. But if you try and put ‘self’ into the call, you get an error saying it expected 2 positional arguments but 3 were given. Even if you were to call the method from outside the class, you are only expected to provide a single argument.
Equally if you omit the word ‘self’ from the method signature, you get the message that it expected 1 positional arguments but 2 were given.
How to Declare Class Properties
It would appear that to make a property, you assign a value to a variable prefixed with self. Anywhere in the class, and at any time.
myVar = 12
is a temporary variable which disappears as soon as it goes out of scope – I hope.
self.myVar = 12
is a property which is now publicly accessible as a class variable from either inside or outside the class.
Again the C purist is harumphing, but we are not trying to write C here – get back in your cage. I will try and abuse it over the rest of the project, and find out what the limits are.
Class Properties
It looks like it is a very good idea to only instantiate properties in the init. Otherwise you cannot guarantee they have been instantiated and may not yet exist when you call them.
I made the Duck class below as an example.
‘species’ and ‘colour’ are declared in the init, so are available throughout the life of the class. If you look down in main() you will see that we can print the duckId immediately after the class is instantiated.
If you remove the second last line, the one that runs randomProp(), then the script will error. Put the line back in, and now the script will run successfully.
Purist or no purist, I think this is a valid place to harumph. This could be a nasty gotcha if you are not careful.
class Duck():
def __init__(self, species, colour):
self.species = species
self.colour = colour
self.generateId(species)
def generateId(self, species):
newId = species + "12345"
self.duckId = newId
def randomProp(self): # This method is not called at init
self.someProp = 42
def main():
# Send in the duck species and colour
myDuck = Duck("Mallard", "Brown")
# Print the duck ID
print(myDuck.duckId)
myDuck.randomProp() # Remove this line, and then the next line will error
print(myDuck.someProp)