tags:

views:

77

answers:

3

Let's suppose I have several functions for a RPG I'm working on...

def name_of_function():
     action

and wanted to implement axe class (see below) into each function without having to rewrite each class. How would I create the class as a global class. I'm not sure if I'm using the correct terminology or not on that, but please help. This has always held me abck from creating Text based RPG games. An example of a global class would be awesome!

class axe:
    attack = 5
    weight = 6
    description = "A lightweight battle axe."
    level_required = 1
    price = 10
+1  A: 

You can't create anything that's truly global in Python - that is, something that's magically available to any module no matter what. But it hardly matters once you understand how modules and importing work.

Typically, you create classes and organize them into modules. Then you import them into whatever module needs them, which adds the class to the module's symbol table.

So for instance, you might create a module called weapons.py, and create a WeaponBase class in it, and then Axe and Broadsword classes derived from WeaponsBase. Then, in any module that needed to use weapons, you'd put

import weapons

at the top of the file. Once you do this, weapons.Axe returns the Axe class, weapons.Broadsword returns the Broadsword class, and so on. You could also use:

from weapons import Axe, Broadsword

which adds Axe and Broadsword to the module's symbol table, allowing code to do pretty much exactly what you are saying you want it to do.

You can also use

from weapons import *

but this generally is not a great idea for two reasons. First, it imports everything in the module whether you're going to use it or not - WeaponsBase, for instance. Second, you run into all kinds of confusing problems if there's a function in weapons that's got the same name as a function in the importing module.

There are a lot of subtleties in the import system. You have to be careful to make sure that modules don't try to import each other, for instance. And eventually your project gets large enough that you don't want to put all of its modules in the same directory, and you'll have to learn about things like __init__.py. But you can worry about that down the road.

Robert Rossney
So are you saying that I would have classes inside of classes, when you said the word "derive"?
Noah Brainey
Of course you can create something that's truly global in Python, using the global keyword.
Rafe Kettler
So it would look soemthing like this isnide of the file weapons.py class weapons: class axe_1: level_required = 2 attack = 4 description = "A lightweight battle axe with a wooden base and a bronze blade." durability = 10 weight = 2
Noah Brainey
@Noah - I think you should read up on object oriented programming. `Derived class` is a simple object oriented concept.
Falmarri
@Rafe - Variables declared with the `global` keyword are still module-scoped. You can't say `global foo` in `bar.py` and have `baz.py` recognize it.
Robert Rossney
If `baz.py` wants access to a global in `bar.py`, it'll import it. In which case, the global in bar becomes globally available (albeit within a module namespace) in baz.
Rafe Kettler
Sure. But that's a definition of "global" that's constrained to Python. In a lot of languages, just including a file in your project is enough to make its globals visible within any module. In Python, each module has to explicitly import another module to gain access to its globals. Also, using `global` doesn't actually address the question of classes, since all module-level classes can be accessed using the `module.class` syntax.
Robert Rossney
A: 

i beg to differ with the view that you can't create something truly global in python. in fact, it is easy. in Python 3.1, it looks like this:

def get_builtins():
  """Due to the way Python works, ``__builtins__`` can strangely be either a module or a dictionary,
  depending on whether the file is executed directly or as an import. I couldn’t care less about this
  detail, so here is a method that simply returns the namespace as a dictionary."""
  return getattr( __builtins__, '__dict__', __builtins__ )

like a bunch of other things, builtins are one point where Py3 differs in details from the way it used to work in Py2. read the "What's New in Python X.X" documents on python.org for details. i have no idea what the reason for the convention mentioned above might be; i just want to ignore that stuff. i think that above code should work in Py2 as well.

so the point here is there is a __builtins__ thingie which holds a lot of stuff that comes as, well, built-into Python. all the sum, max, range stuff you've come to love. well, almost everything. but you don't need the details, really. the simplest thing you could do is to say

G          = get_builtins()
G[ 'G' ]   = G
G[ 'axe' ] = axe

at a point in your code that is always guaranteed to execute. G stands in for the globally available namespace, and since i've registered G itself within G, G now magically transcends its existence into the background of every module. means you should use it with care. where naming collisions occur between whatever is held in G and in a module's namespace, the module's namespace should win (as it gets inspected first). also, be prepared for everybody to jump on you when you tell them you're POLLUTING THE GLOBAL NAMESPACE dammit. i'm relly surprised noone has copmplained about that as yet, here.

well, those people would be quite right, in a way. personally, however, this is one of my main application composition techniques: what you do is you take a step away from the all-purpose module (which shouldn't do such a thing) towards a fine-tuned application-specific namespace. your modules are bound not to work outside that namespace, but then they're not supposed to, either. i actually started this style of programming as an experimental rebellion against (1) established views, hah!, and (2) the desperation that befalls me whenever i want to accomplish something less than trivial using Python's import statement. these days, i only use import for standard library stuff and regularly-installed modules; for my own stuff, i use a homegrown system. what can i say, it works!

ah yes, two more points: do yourself a favor, if you like this solution, and write yourself a publish() method or the like that oversees you never publish a name that has already been taken. in most cases, you do not want that.

lastly, let me second the first commenter: i have been programming in exactly the style you show above, coz that's what you find in the textbook examples (most of the time using cars, not axes to be sure). for a rather substantial number of reasons, i've pretty much given up on that.

consider this: JSON defines but seven kinds of data: null, true, false, numbers, texts, lists, dictionaries, that's it. i claim you can model any other useful datatype with those.

there is still a lot of justification for things like sets, bags, ordered dictionaries and so on. the claim here is not that it is always convenient or appropriate to fall back on a pure, directly JSON-compatible form; the claim is only that it is possible to simulate. right now, i'm implementing a sparse list for use in a messaging system, and that data type i do implement in classical OOP. that's what it's good for.

but i never define classes that go beyond these generic datatypes. rather, i write libraries that take generic datatypes and that provide the functionality you need. all of my business data (in your case probably representations of players, scenes, implements and so on) go into generic data container (as a rule, mostly dicts). i know there are open questions with this way of architecturing things, but programming has become ever so much easier, so much more fluent since i broke thru the BS that part of OOP propaganda is (apart from the really useful and nice things that another part of OOP is).

oh yes, and did i mention that as long as you keep your business data in JSON-compatible objects you can always write them to and resurrect them from the disk? or send them over the wire so you can interact with remote players? and how incredibly twisted the serialization business can become in classical OOP if you want to do that (read this for the tip of the iceberg)? most of the technical detail you have to know in this field is completely meaningless for the rest of your life.

flow
A: 

You can add (or change existing) Python built-in functions and classes by doing either of the following, at least in Py 2.x. Afterwards, whatever you add will available to all code by default, although not permanently.

Disclaimer: Doing this sort of thing can be dangerous due to possible name clashes and problematic due to the fact that it's extremely non-explicit. But, hey, as they say, we're all adults here, right?

class MyCLass: pass

# one way
setattr(__builtins__, 'MyCLass', MyCLass)

# another way
import __builtin__
__builtin__.MyCLass = MyCLass
martineau
say you're having builtin (singular) and builtins (plural) here. i never understood the thinking that caused the difference between those two, and somehow i think the singular one is gone in py3.1, is it? anyone wanting to comment?
flow
@flow: Here's my guess. As the docs say "Most modules have the name `__builtins__` (note the 's') made available as part of their globals", therefore the `__builtin__` module was given a (slightly) different name so it could coexist in the same namespace (as in not hide the former or vice-versa).
martineau