Python-passing variable between classes - python

I'm trying to create a character generation wizard for a game. In one class I calculate the attributes of the character. In a different class, I'm displaying to the user which specialties are available based on the attributes of the character. However, I can't remember how to pass variables between different classes.
Here is an example of what I have:
class BasicInfoPage(wx.wizard.WizardPageSimple):
def __init__(self, parent, title):
wiz.WizardPageSimple.__init__(self, parent)
self.next = self.prev = None
self.sizer = makePageTitle(self, title)
<---snip--->
self.intelligence = self.genAttribs()
class MOS(wx.wizard.WizardPageSimple):
def __init__(self, parent, title):
wiz.WizardPageSimple.__init__(self, parent)
self.next = self.prev = None
self.sizer = makePageTitle(self, title)
def eligibleMOS(self, event):
if self.intelligence >= 12:
self.MOS_list.append("Analyst")
The problem is that I can't figure out how to use the "intelligence" variable from the BasicInfoPage class to the MOS class. I've tried several different things from around the Internet but nothing seems to work. What am I missing?
Edit I realized after I posted this that I didn't explain it that well. I'm trying to create a computer version of the Twilight 2000 RPG from the 1980s.
I'm using wxPython to create a wizard; the parent class of my classes is the Wizard from wxPython. That wizard will walk a user through the creation of a character, so the Basic Information page (class BasicInfoPage) lets the user give the character's name and "roll" for the character's attributes. That's where the "self.intelligence" comes from.
I'm trying to use the attributes created her for a page further on in the wizard, where the user selects the speciality of the character. The specialities that are available depend on the attributes the character has, e.g. if the intelligence is high enough, the character can be an Intel Anaylst.
It's been several years since I've programmed, especially with OOP ideas. That's why I'm confused on how to create what's essentially a global variable with classes and methods.

You may have "Class" and "Instance" confused. It's not clear from your example, so I'll presume that you're using a lot of class definitions and don't have appropriate object instances of those classes.
Classes don't really have usable attribute values. A class is just a common set of definitions for a collection of objects. You should think of of classes as definitions, not actual things.
Instances of classes, "objects", are actual things that have actual attribute values and execute method functions.
You don't pass variables among classes. You pass variables among instances. As a practical matter only instance variables matter. [Yes, there are class variables, but they're a fairly specialized and often confusing thing, best avoided.]
When you create an object (an instance of a class)
b= BasicInfoPage(...)
Then b.intelligence is the value of intelligence for the b instance of BasicInfoPage.
A really common thing is
class MOS( wx.wizard.PageSimple ):
def __init__( self, parent, title, basicInfoPage ):
<snip>
self.basicInfo= basicInfoPage
Now, within MOS methods, you can say self.basicInfo.intelligence because MOS has an object that's a BasicInfoPage available to it.
When you build MOS, you provide it with the instance of BasicInfoPage that it's supposed to use.
someBasicInfoPage= BasicInfoPage( ... )
m= MOS( ..., someBasicInfoPage )
Now, the object m can examine someBasicInfoPage.intelligence

Each page of a Wizard -- by itself -- shouldn't actually be the container for the information you're gathering.
Read up on the Model-View-Control design pattern. Your pages have the View and Control parts of the design. They aren't the data model, however.
You'll be happier if you have a separate object that is "built" by the pages. Each page will set some attributes of that underlying model object. Then, the pages are independent of each other, since the pages all get and set values of this underlying model object.
Since you're building a character, you'd have some class like this
class Character( object ):
def __init__( self ):
self.intelligence= 10
<default values for all attributes.>
Then your various Wizard instances just need to be given the underlying Character object as a place to put and get values.

My problem was indeed the confusion of classes vs. instances. I was trying to do everything via classes without ever creating an actual instance. Plus, I was forcing the "BasicInfoPage" class to do too much work.
Ultimately, I created a new class (BaseAttribs) to hold all the variables I need. I then created in instance of that class when I run the wizard and pass that instance as an argument to the classes that need it, as shown below:
#---Run the wizard
if __name__ == "__main__":
app = wx.PySimpleApp()
wizard = wiz.Wizard(None, -1, "TW2K Character Creation")
attribs = BaseAttribs
#---Create each page
page1 = IntroPage(wizard, "Introduction")
page2 = BasicInfoPage(wizard, "Basic Info", attribs)
page3 = Ethnicity(wizard, "Ethnicity")
page4 = MOS(wizard, "Military Occupational Specialty", attribs)
I then used the information S.Lott provided and created individual instances (if that's what it's called) within each class; each class is accessing the same variables though.
Everything works, as far as I can tell. Thanks.

All you need is a reference. It's not really a simple problem that I can give some one-line solution to (other than a simple ugly global that would probably break something else), but one of program structure. You don't magically get access to a variable that was created on another instance of another class. You have to either give the intelligence reference to MOS, or take it from BasicInfoPage, however that might happen. It seems to me that the classes are designed rather oddly-- an information page, for one thing, should not generate anything, and if it does, it should give it back to whatever needs to know-- some sort of central place, which should have been the one generating it in the first place. Ordinarily, you'd set the variables there, and get them from there. Or at least, I would.
If you want the basic answer of "how do I pass variables between different classes", then here you go, but I doubt it's exactly what you want, as you look to be using some sort of controlling framework:
class Foo(object):
def __init__(self, var):
self.var = var
class Bar(object):
def do_something(self, var):
print var*3
if __name__ == '__main__':
f = Foo(3)
b = Bar()
# look, I'm using the variable from one instance in another!
b.do_something(f.var)

If I understood you correctly, then the answer is: You can't.
intelligence should be an attribute of WizardPageSimple, if you'd want both classes to inherit it.
Depending on your situation, you might try to extract intelligence and related attributes into another baseclass. Then you could inherit from both:
class MOS(wiz.WizardPageSimple, wiz.IntelligenceAttributes): # Or something like that.
In that case you must use the co-operative super. In fact, you should be using it already. Instead of calling
wiz.WizardPageSimple.__init__(self, parent)
call
super(MOS, self).__init__(self, parent)

Related

Python class and methods - best practice for accessing and altering attributes?

TLDR: What's best practice for accessing and altering attributes of a class instance?
Let's say we have a class to generate an object that is intended to hold data about a product (e.g. maybe a product master dataset).
class StoreProduct(object):
def __init__(self,ProductID,ProductPrice,ProductDescription):
self.ProductID = ProductID
self.ProductPrice = ProductPrice
self.ProductDescription = ProductDescription
def ChangeProductPrice(self, newProductPrice):
self.ProductPrice = newProductPrice
And we have another class we may be able to use to access those instances generated by StoreProduct(), with methods for making adjustments / changes.
class ChangeProductData(object):
def __init__(self):
pass
#staticmethod
def ChangeProductObjectPrice(newProductPrice,ProductObject):
ProductObject.ProductPrice = newProductPrice
So we generate an instance named Product1:
Product1 = StoreProduct(
ProductID="Product1",
ProductPrice=4,
ProductDescription="A nice lamp"
)
What's best practice coding for reading and/or altering class instances?
If I wanted to alter an attribute in Product 1 (in this case the price) is something like this acceptable in general, or is it bad code?
Method 1
ChangeProductData().ChangeProductObjectPrice(8,Product1)
Or is this the preferred way to do it?
Method 2
Product1.ChangeProductPrice(2)
When might there be exceptions?
While the above are simplified situations, what I've currently read seems to indicate that Method 2 might be better practice. However, wouldn't Method 1 provide greater flexibility in future (e.g. if you need to change how a method works, or add new methods).
I have also been reading into getattr() and setattr(), but people seem to be mixed on whether its better than using dot (e.g. Product1.ProductPrice to get the price).
Definitely method 2. As #user2357112 mentions, method 1 doesn't make sense.
As you rightly pointed out, this is a simple scenario and the pythonic way would be use property
class StoreProduct(object): # minor: please notice the PEP styling
def __init__(self, product_price):
self._price = produce_price
# other attributes, omitted for brevity
#property
def product_price(self): # pythonic getter
return self._price
#product_price.setter
def product_price(self, new_price): # python setter
# you could do any custom validation before setting
self._price = new_price
Coming to the question of
I'm specifically tackling the issue of whether accessing and altering an class' attribute with another class is a big no-no.
Accessing: Accessing is okay here. In fact many design patterns that rely on composition heavily do this. e.g., adapter, strategy, decorator, command etc patterns
Altering: You want the class owning the attribute to be in charge of "altering". Foreign classes should only request to alter.
P.S. This is treading a bit along the lines of CQRS(Command Query Responsibility Segregation) pattern

Keeping classes loosely coupled and sharing data

I've been working in python on a project where I have a GUI which I split up a bunch of the work between classes. I don't know a lot of the best practices for passing data around between classes, and I've frequently run into the issue, where I have to implement something, or change something for work, and I've resorted to making a lot of the classes objects of another class in order to give it the data I need.
Any ideas or suggests would be greatly appreciated on how to keep my classes independent for later modification and still pass the relevant data around without affecting interfaces too much?
As an example
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork(Window):
def __init__(self, parent=None):
self.parent=parent
I often find myself doing stuff like the above giving objects to class Window
or simply inheriting everything from them as in ParseMyWork
There must be better and cleaner ways of passing data around without making my classes utterly dependent on eachother, where one little change creates a cascade effect that forces me to make changes in a bunch of other classes.
Any answers to the question don't necessarily have to be in python, but it will be helpful if they are
If I'm understanding your question correctly, I would say that inheritance is not necessary in your case. Why not give ParseMyWork a function for dealing with a specific Window task?
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork():
def __init__(self, parent=None):
self.parent=parent`
def doWindowActivity(self, window):
window.doStuff
Then you can use the function like this
work_parser = ParseMyWork()
window = Window()
work_parser.doWindowActivity(window);
That way you can use your work_parse instance with any window instance.
Apologies in advance for my Python, it's been a while so if you see any rookie mistakes, do point them out.
Keep it simple.py:
def doStuff(window):
#do work here
return window
def parseStuff(stuff):
pass
really.py:
from simple import doStuff, parseStuff
def really_simple(window):
okay = doStuff(window)
return parseStuff(okay)
don't complicate the class:
from really import really_simple
really_simple(window)
imo: classes are overly complicated objects, and in a lot of cases more confusing than they need to be, plus they hold references and modify stuff, and can be difficult to decouple once they have been tied to other classes. if there isn't a clear reason why a class needs to be used, then it probably doesn't need to be used.
Classes are super powerful, so it's good you're getting started with em.
Discalimer: Haven't worked in python for a while now, so things might not be exact. The general idea still applies though.
Getting into your question now:
I would say the best way to achieve what you want is to create an instance of the first object where you will extract information from.
Now when creating a class, it's vital that you have attributes within them that you will want to be stored within it that you would like to retrieve once the class is instantiated.
For example, using your Window class example above, let's say that you have an attribute called resolution. It would look something like this:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
Now the resolution information associated with your Window class is forever part of any Window class instance. Now, the next step would be to create a get method for resolution. This should be done as follow:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
def getResoultion():
return self.resolution
Now, the reason we created this get method is because we can now set a variable to the information that is returned with it.
So let's say that you have everything associated with your Window class in its own file (let's say the file name is called Window.py). In a separate file (let's call it main.py), you can do the following:
import Window
windowInstance = Window()
windowResolution = windowInstance.getResolution()
If you print out the variable windowResolution, you should get that 40x80 printed out.
Now, as a side note, I do believe it is possible to get the information associated with an attribute with an instance of a class by simply doing something like
windowResolution = windowInstance.resolution
but that is bad practice in general. The reason, in a nutshell, is because you are now exposing attribute names of your class which you do not want to do because it makes it easy for a person outside of your code to learn the name where that information is held and change it. This can then lead to a myriad of other problems when it comes to making an overall program work. That is why it is best practice to use getters and setters. I already showed what getters are. Simply a get method for attributes. Setters, as you can probably assume, allow for one to set the information of an attribute to something else. Now you might say "Gabe, if we can create setter methods, what's the point of it if they just change it". My answer to that is to not give a setter method to all attributes. For attributes you don't mind for a person to change, give it a setter method, but for attributes you do not want any outside users to touch, simply don't create a setter method for it. Same goes with getter methods too. Users don't need to see all of the information of all attributes that makes your program work. Here's a better explanation: https://en.wikipedia.org/wiki/Mutator_method
Now, back to your example. Now let's say you have your ParseMyWork class in its own file like we did with your Window class, and let's say that ParseMyWork needs the resolution info from Window class. You can do the following :
import Window
import ParseMyWork
windowInstance = Window()
windowResolution = windowInstance.getResolution()
parseInstance = ParseMyWork(windowResolution)
This will only pass the window resolution information associated with your Window class. Hope this helps.

What is the proper way to add an attribute to a base class in a Python library and have it inherited?

I am trying to extend a Python library to add functionality I desire. The library provides a number of HTML form objects (such as Textbox, Dropdown, Checkbox, etc.), all derived from an Input object. I want to add an additional attribute to all of these derived objects. What is the proper way of proceeding?
I can:
Modify the original source code for the Input class, adding the attribute I want.
Create a new class that inherits Input and adds my attribute, and then create a bunch of new classes that inherit Textbox, Dropdown, and my new Input class.
Create new classes for Textbox, Dropdown, etc. with the attribute.
Solution 1 is the easiest and simplest, but is inherently wrong, whereas the other two seem like much more work and code-repetition than this task should call for.
Is there a solution I'm missing?
The 4th solution is monkey patching and might be a good idea. Before you try this, make sure this won't break anything now or in the future:
def additional_method(self, arg):
print("hello", arg)
Input.additional_method = additional_method
or for short stuff:
Input.additional_method = lambda self, arg: do_something(arg)
now all existing and future Input instances (and therefore instances of all Input subclasses) have an additional_method attached to them.
This works also for any future subclasses of Input that might not even exist yet, or you might not be aware of, at the time of adding the method, so is therefore better (i.e. more generic) than creating an alternative inheritance hierarchy, which you'll have to then maintain and keep in sync with upstream changes.
NOTE: before you downvote just because it contains the phrase "monkey patching", consider that monkey patching doesn't have to be dangerous/fragile, and is a first class (as in "respected") feature in many languages.
You can use a mixin (multiple inheritance). It's a class that just contains your extra attribute, and add this class to the parent class of a subclass of Textbox, Dropdown, Checkbox... like this:
from ... import TextBox
class Mixin:
def __init__(self):
self.new_attribude = ...
class TextBox_with_new_attribute(Mixin, TextBox):
pass
But, it depends tightly on your goals...
Edit: base on #Veedrac comment, in case of third party library.
If there are a lot of classes you could dynamically apply a mixin:
for cls in list_of_classes_to_patch:
patched = type(cls.__name__, (my_mixin, cls), {})
setattr(place_to_export, cls.__name__, patched)
place_to_export can be defined as import this_module as place_to_export.

What is the correct way to extend a parent class method in modern Python

I frequently do this sort of thing:
class Person(object):
def greet(self):
print "Hello"
class Waiter(Person):
def greet(self):
Person.greet(self)
print "Would you like fries with that?"
The line Person.greet(self) doesn't seem right. If I ever change what class Waiter inherits from I'm going to have to track down every one of these and replace them all.
What is the correct way to do this is modern Python? Both 2.x and 3.x, I understand there were changes in this area in 3.
If it matters any I generally stick to single inheritance, but if extra stuff is required to accommodate multiple inheritance correctly it would be good to know about that.
You use super:
Return a proxy object that delegates
method calls to a parent or sibling
class of type. This is useful for
accessing inherited methods that have
been overridden in a class. The search
order is same as that used by
getattr() except that the type itself
is skipped.
In other words, a call to super returns a fake object which delegates attribute lookups to classes above you in the inheritance chain. Points to note:
This does not work with old-style classes -- so if you are using Python 2.x, you need to ensure that the top class in your hierarchy inherits from object.
You need to pass your own class and instance to super in Python 2.x. This requirement was waived in 3.x.
This will handle all multiple inheritance correctly. (When you have a multiple inheritance tree in Python, a method resolution order is generated and the lookups go through parent classes in this order.)
Take care: there are many places to get confused about multiple inheritance in Python. You might want to read super() Considered Harmful. If you are sure that you are going to stick to a single inheritance tree, and that you are not going to change the names of classes in said tree, you can hardcode the class names as you do above and everything will work fine.
Not sure if you're looking for this but you can call a parent without referring to it by doing this.
super(Waiter, self).greet()
This will call the greet() function in Person.
katrielalex's answer is really the answer to your question, but this wouldn't fit in a comment.
If you plan to go about using super everywhere, and you ever think in terms of multiple inheritance, definitely read the "super() Considered Harmful" link. super() is a great tool, but it takes understanding to use correctly. In my experience, for simple things that don't seem likely to get into complicated diamond inheritance tangles, it's actually easier and less tedious to just call the superclass directly and deal with the renames when you change the name of the base class.
In fact, in Python2 you have to include the current class name, which is usually more likely to change than the base class name. (And in fact sometimes it's very difficult to pass a reference to the current class if you're doing wacky things; at the point when the method is being defined the class isn't bound to any name, and at the point when the super call is executed the original name of the class may not still be bound to the class, such as when you're using a class decorator)
I'd like to make it more explicit in this answer with an example. It's just like how we do in JavaScript. The short answer is, do that like we initiate the constructor using super.
class Person(object):
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, I'm {self.name}")
class Waiter(Person):
def __init__(self, name):
super().__init__(name)
# initiate the parent constructor
# or super(Waiter, self).__init__(name)
def greet(self):
super(Waiter, self).greet()
print("Would you like fries with that?")
waiter = Waiter("John")
waiter.greet()
# Hello, I'm John
# Would you like fries with that?

Need help with the class and instance concept in Python

I have read several documentation already but the definition of "class" and "instance" didnt get really clear for me yet.
Looks like that "class" is like a combination of functions or methods that return some result is that correct? And how about the instance? I read that you work with the class you creat trough the instance but wouldnt be easier to just work direct with the class?
Sometimes geting the concepts of the language is harder than working with it.
Your question is really rather broad as classes and instances/objects are vital parts of object-oriented programming, so this is not really Python specific. I recommend you buy some books on this as, while initially basic, it can get pretty in-depth. In essense, however:
The most popular and developed model of OOP is a class-based model, as opposed to an object-based model. In this model, objects are entities that combine state (i.e., data), behavior (i.e., procedures, or methods) and identity (unique existence among all other objects). The structure and behavior of an object are defined by a class, which is a definition, or blueprint, of all objects of a specific type. An object must be explicitly created based on a class and an object thus created is considered to be an instance of that class. An object is similar to a structure, with the addition of method pointers, member access control, and an implicit data member which locates instances of the class (i.e. actual objects of that class) in the class hierarchy (essential for runtime inheritance features).
So you would, for example, define a Dog class, and create instances of particular dogs:
>>> class Dog():
... def __init__(self, name, breed):
... self.name = name
... self.breed = breed
... def talk(self):
... print "Hi, my name is " + self.name + ", I am a " + self.breed
...
>>> skip = Dog('Skip','Bulldog')
>>> spot = Dog('Spot','Dalmatian')
>>> spot.talk()
Hi, my name is Spot, I am a Dalmatian
>>> skip.talk()
Hi, my name is Skip, I am a Bulldog
While this example is silly, you can then start seeing how you might define a Client class that sets a blueprint for what a Client is, has methods to perform actions on a particular client, then manipulate a particular instance of a client by creating an object and calling these methods in that context.
Sometimes, however, you have methods of a class that don't really make sense being accessed through an instance of the class, but more from the class itself. These are known as static methods.
I am not sure of what level of knowledge you have, so I apologize if this answer is too simplified (then just ignore it).
A class is a template for an object. Like a blueprint for a car. The instance of a class is like an actual car. So you have one blueprint, but you can have several different instances of cars. The blueprint and the car are different things.
So you make a class that describes what an instance of that class can do and what properties it should have. Then you "build" the instance and get an object that you can work with.
It's fairly simple actually. You know how in python they say "everything is an object". Well in simplistic terms you can think of any object as being an 'instance' and the instructions to create an object as the class. Or in biological terms DNA is the class and you are an instance of DNA.
class HumanDNA(): # class
... class attributes ...
you = HumanDNA() # instance
See http://homepage.mac.com/s_lott/books/python/htmlchunks/ch21.html
Object-oriented programming permits us
to organize our programs around the
interactions of objects. A class
provides the definition of the
structure and behavior of the objects;
each object is an instance of a class.
Objects ("instances") are things which interact, do work, persist in the file system, etc.
Classes are the definitions for the object's behavior.
Also, a class creates new objects that are members of that class (share common structure and behavior)
In part it is confusing due to the dynamically typed nature of Python, which allows you to operate on a class and an instance in essentially the same way. In other languages, the difference is more concrete in that a class provides a template by which to create an object (instance) and cannot be as directly manipulated as in Python. The benefit of operating on the instance rather than the class is that the class can provide a prototype upon which instances are created.

Categories