Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
reading
Jul 27, 2013
What do @classmethod and @property mean?

Adbot
ADBOT LOVES YOU

Telarra
Oct 9, 2012

@classmethod
@property

The @ syntax means they're decorators. Decorators are used when you define a function to 'decorate' it; the decorator is a function that receives your new function as a parameter, and returns what will actually be defined.

i.e. this:
Python code:
class Foo(object):
    @classmethod
    def a_static_method(cls, some_arg):
        ...
is equivalent to this:
Python code:
class Foo(object):
    def a_static_method(cls, some_arg):
        ...
    a_static_method = classmethod(a_static_method)
So you use @classmethod to easily mark methods as what are known in other languages as static methods - they operate on the class instead of on a particular instance.

And @property is used to simplify defining a very common pattern in OOP: the property. In OO languages without properties, you often end up writing stuff like this:
Python code:
class Foo(object):
    def __init__(self, val):
        self._val = val

    def get_val(self):
        return self._val

    def set_val(self, val):
        self._val = val
The benefit to this over just accessing foo._val directly is that you can add extra logic around it, or otherwise change how 'val' is implemented without having to change all the code that uses this class. The downside is that the syntax for accessing it is different (foo.get_val() instead of foo.val and foo.set_val(5) instead of foo.val = 5), which means upgrading a variable to using a getter+setter still means changing all the code that uses it. So it's good practice to implement every public-facing variable with a getter+setter, even though it's extra work and the syntax for your class's interface will be wordier and messier.
Properties give you the best of both worlds:
Python code:
class Foo(object):
    def __init__(self, val):
        self._val = val

    @property
    def val(self):
        return self._val

    @val.setter
    def val(self, val):
        self._val = val
Now you can access foo._val as just foo.val, and it will call the setter and getter functions to do so. Simple!

ShadowHawk
Jun 25, 2000

CERTIFIED PRE OWNED TESLA OWNER

Moddington posted:

@classmethod
@property

The @ syntax means they're decorators. Decorators are used when you define a function to 'decorate' it; the decorator is a function that receives your new function as a parameter, and returns what will actually be defined.

i.e. this:
Python code:
class Foo(object):
    @classmethod
    def a_static_method(cls, some_arg):
        ...
is equivalent to this:
Python code:
class Foo(object):
    def a_static_method(cls, some_arg):
        ...
    a_static_method = classmethod(a_static_method)
So you use @classmethod to easily mark methods as what are known in other languages as static methods - they operate on the class instead of on a particular instance.
You use @classmethod to indicate class methods, yes, but the actual name for them (in python) is the much more sensible class methods. "Static methods" are something different:
Python code:
class Foo():
  @staticmethod
  def a_real_static_method(some_arg):
    ...
Static methods do not get passed the implicit reference to self as their first argument like instance methods, nor the implicit reference to the class like class methods. Instead they behave exactly like normal functions defined outside of a class variable.

What's the point? It's mostly to get them out of the common namespace so you can put a class-relevant function inside a class even if you don't need to actually reference the class/instance itself.

ShadowHawk
Jun 25, 2000

CERTIFIED PRE OWNED TESLA OWNER
I'm beginning to rethink the earlier comments we had against circular references in classes. I think it might be entirely reasonable in a few cases.

For instance, a tree could have each node reference both itself and its parent.
Python code:
class Node():
  def __init__(self, parent):
    self.parent = parent
  def spawn(self):
    new_node = Node(self)
Apparently Python's garbage collector is smart enough to deal with circular references like this (if, say, parent goes out of scope or gets deleted), unless you define a custom __del__ method.

BigRedDot
Mar 6, 2008

Python also provides weakref's, that won't bump the reference count, which can be useful for object graphs that have cycles. Have you guys really never encountered object graph data structures that have back references? Maybe not the most common things, but it still seems wholly unremarkable to me.

accipter
Sep 12, 2003

BigRedDot posted:

Python also provides weakref's, that won't bump the reference count, which can be useful for object graphs that have cycles. Have you guys really never encountered object graph data structures that have back references? Maybe not the most common things, but it still seems wholly unremarkable to me.

They are really common in GUI objects. In PySide, nearly everything is based on QObject which has a parent() method.

Jose Cuervo
Aug 25, 2004
I am trying to use the networkx package. I have successfully installed networkx (I can go through the tutorial examples), but the following code where I try to read in a graph from a GIS shapefile:
Python code:
import networkx as nx

G = nx.read_shp('shapefiles/roads.shp')
results in the following error:
code:
File "C:Python27\lib\site-packages\networkx\readwrite\nx_shp.py", line 56, in read_shp
    raise ImportError("read_shp requires OGR: [url]http://www.gdal.org/[/url]")
ImportError: read_shp requires OGR: [url]http://www.gdal.org/[/url]
The ImportError is thrown as a result of reaching the following lines in the file nx_shp.py:
Python code:
try:
    from osgeo import ogr
except ImportError:
    raise ImportError("read_shp requires OGR: [url]http://www.gdal.org/[/url]")
I successfully installed gdal and ogr (contained in the osgeo package) using the instructions found here, where successful means that the statement
Python code:
from osgeo import ogr
does not throw errors when executed in Idle. However running the original code at the top still produces the same ImportError.

Anyone know what I might be doing wrong?

Jose Cuervo fucked around with this message at 23:24 on Dec 24, 2014

Hed
Mar 31, 2004

Fun Shoe
Your paths probably aren't the same in each case--try looking at sys.path in IDLE and the same at the top of your script.

accipter
Sep 12, 2003

Jose Cuervo posted:

Anyone know what I might be doing wrong?

Did you restart IDLE after you modified the environment variables?

Jose Cuervo
Aug 25, 2004

Hed posted:

Your paths probably aren't the same in each case--try looking at sys.path in IDLE and the same at the top of your script.

In Idle:
Python code:
>>> import sys
>>> sys.path
['', 'C:\\Python27\\Lib\\idlelib', 'C:\\Python27\\lib\\site-packages\\setuptools-2.0.1-py2.7.egg', 
'C:\\Windows\\system32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 
'C:\\Python27\\lib\\lib-tk', 'C:\\Python27', 'C:\\Python27\\lib\\site-packages']
In the script (located in a folder named "trial_code" on the desktop):
Python code:
import sys
print sys.path
['', 'C:\\Users\\JoseCuervo\\Desktop\\trial_code', 'C:\\Python27\\lib\\site-packages\\setuptools-2.0.1-py2.7.egg', 
'C:\\Windows\\system32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 
'C:\\Python27\\lib\\lib-tk', 'C:\\Python27', 'C:\\Python27\\lib\\site-packages']
Both calls to sys.path seem to produce the same output, however I am not quite sure what I should be looking for. Thoughts?

accipter posted:

Did you restart IDLE after you modified the environment variables?
I have restarted Idle but not the computer. I did install the networkx package before the osgeo package. I will try restarting the computer.

EDIT: Bah. Restarting seems to have done the trick. Not sure why I needed to do that, but oh well.

Jose Cuervo fucked around with this message at 04:37 on Dec 25, 2014

QuarkJets
Sep 8, 2008

Jose Cuervo posted:

In Idle:
Python code:
>>> import sys
>>> sys.path
['', 'C:\\Python27\\Lib\\idlelib', 'C:\\Python27\\lib\\site-packages\\setuptools-2.0.1-py2.7.egg', 
'C:\\Windows\\system32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 
'C:\\Python27\\lib\\lib-tk', 'C:\\Python27', 'C:\\Python27\\lib\\site-packages']
In the script (located in a folder named "trial_code" on the desktop):
Python code:
import sys
print sys.path
['', 'C:\\Users\\JoseCuervo\\Desktop\\trial_code', 'C:\\Python27\\lib\\site-packages\\setuptools-2.0.1-py2.7.egg', 
'C:\\Windows\\system32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 
'C:\\Python27\\lib\\lib-tk', 'C:\\Python27', 'C:\\Python27\\lib\\site-packages']
Both calls to sys.path seem to produce the same output, however I am not quite sure what I should be looking for. Thoughts?

I have restarted Idle but not the computer. I did install the networkx package before the osgeo package. I will try restarting the computer.

EDIT: Bah. Restarting seems to have done the trick. Not sure why I needed to do that, but oh well.

Probably something was being changed to your PYTHONPATH, but only after a restart for some reason

reading
Jul 27, 2013
Hi again, I'm still doing libtcod + python roguelike stuff. I am trying to access a specific character in this tileset:



I'm using it for the graphics and libtcod handles it just fine, however I want to specify one of the really weird characters at the bottom, from the family of stuff that looks like a collection of double pipe segments along three rows. How do I refer to these things? They don't show up in my system's character map utility since this is not a system font, and they don't have ASCII codes either. How do I specify an element in this font matrix?

I think I'm using UTF-8 encoding for my program because its the default and I haven't defined anything else.

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord

reading posted:

Hi again, I'm still doing libtcod + python roguelike stuff. I am trying to access a specific character in this tileset:



I'm using it for the graphics and libtcod handles it just fine, however I want to specify one of the really weird characters at the bottom, from the family of stuff that looks like a collection of double pipe segments along three rows. How do I refer to these things? They don't show up in my system's character map utility since this is not a system font, and they don't have ASCII codes either. How do I specify an element in this font matrix?

I think I'm using UTF-8 encoding for my program because its the default and I haven't defined anything else.

Unless I'm wrong this seems to be Code page 437. Wikipedia has all the characters in unicode: http://en.wikipedia.org/wiki/Code_page_437

reading
Jul 27, 2013

Symbolic Butt posted:

Unless I'm wrong this seems to be Code page 437. Wikipedia has all the characters in unicode: http://en.wikipedia.org/wiki/Code_page_437

After having a lot of trouble getting this to work it looks like unicode is not supported in the python version of libtcod: http://doryen.eptalys.net/data/libtcod/doc/1.5.1/html2/console_print.html#10

However it says that it's the "python wrapper" that doesn't support it, but it gives examples for C and C++. It's really going to be a bummer if I can't use the whole roguelike tileset, such as Greek lowercase "alpha" for fish, and so on. Do I have any options here, such as using the C/C++ functions in my python code somehow to access and display those characters?

This post on the official libtcod forums http://roguecentral.org/doryen/forum/index.php?topic=1491.0 is on this topic but only for C++. They use putChar to display characters from fonts with >255 characters.

reading fucked around with this message at 06:56 on Dec 27, 2014

QuarkJets
Sep 8, 2008

reading posted:

After having a lot of trouble getting this to work it looks like unicode is not supported in the python version of libtcod: http://doryen.eptalys.net/data/libtcod/doc/1.5.1/html2/console_print.html#10

However it says that it's the "python wrapper" that doesn't support it, but it gives examples for C and C++. It's really going to be a bummer if I can't use the whole roguelike tileset, such as Greek lowercase "alpha" for fish, and so on. Do I have any options here, such as using the C/C++ functions in my python code somehow to access and display those characters?

This post on the official libtcod forums http://roguecentral.org/doryen/forum/index.php?topic=1491.0 is on this topic but only for C++. They use putChar to display characters from fonts with >255 characters.

Yeah, that's what I would suggest. You could write your own wrappers for libtcod that support unicode. It might not even be that much work, if the C++ functions are relatively straightforward to use

Crosscontaminant
Jan 18, 2007

The Python wrapper is thin as anything - in particular for console_put_char it just takes ord(c) if you pass it str or bytes and passes anything else as-is. All the "ASCII" constants are just defined as numbers between 0 and 255. You don't even need to think about Unicode.

reading
Jul 27, 2013

Crosscontaminant posted:

The Python wrapper is thin as anything - in particular for console_put_char it just takes ord(c) if you pass it str or bytes and passes anything else as-is. All the "ASCII" constants are just defined as numbers between 0 and 255. You don't even need to think about Unicode.

This works! I just pass the values as decimal numbers, rather than as u'\u####' unicode characters.

Literally Elvis
Oct 21, 2013

I'm writing a small django app thing and I need to set a few GET parameters to None if they're not in the URL, is it better to do:

Python code:
args["term"] = request.GET["t"] if request.GET["t"] else None
or
Python code:
if request.GET["t"]:
    args["term"] = request.GET["t"]
I like the first one since I have to do it a few times, but I don't want to give any more reasons for someone to scoff at my code than they normally do.

Literally Elvis fucked around with this message at 17:25 on Dec 31, 2014

Dominoes
Sep 20, 2007

Those bits of code will produce different results if args["term"] is called and request.GET["t"] is false. The first case will return None, and the second will raise a KeyError.

Your second example, changed to match the results of the first:

Python code:
if request.GET["t"]:
    args["term"] = request.GET["t"]
else:
    args["term"] = None
You can't modify the first one to behave as the second, since the syntax shortcut you're using requires the else assignment.

Dominoes fucked around with this message at 17:33 on Dec 31, 2014

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

Literally Elvis posted:

I'm writing a small django app thing and I need to set a few GET parameters to None if they're not in the URL, is it better to do:

Python code:
args["term"] = request.GET["t"] if request.GET["t"] else None
or
Python code:
if request.GET["t"]:
    args["term"] = request.GET["t"]
I like the first one since I have to do it a few times, but I don't want to give any more reasons for someone to scoff at my code than they normally do.

I believe you want to do something like so:

Python code:
t= request.GET.get('t', None)
You could then make a loop of the various params you are looking for and assign them to a dict:

Python code:
params = {} 
expected_params = ['t','a','b', 'z']
for p in expected_params:
    params[p] = request.GET.get(p, None)

Lumpy fucked around with this message at 17:37 on Dec 31, 2014

Literally Elvis
Oct 21, 2013

Dominoes posted:

Those bits of code will produce different results if args["term"] is called and request.GET["t"] is false.

Right, I done goofed, but what you said is what I meant.

Lumpy posted:

I believe you want to do something like so:

Python code:
t= request.GET.get('t', None)

That'll do.

Dominoes
Sep 20, 2007

Lumpy posted:

dict.get()
Cool! Looks like the 'None' second arg is unnecessary.

Elvis, use the shortcut in your first example whenever it's applicable. It looks cleaner than using multiple lines with indentations.

Dominoes fucked around with this message at 18:23 on Dec 31, 2014

reading
Jul 27, 2013
I have a few 2D arrays, "level[x][y]" specifying all the qualities of map tiles for a big (x, y) grid. But now I want to save these maps and keep a list of arrays. At first I thought about just making it 3D, with the first dimension being the order of the maps, but I also thought about using a dict where the key is a string which describes the map (outdoors, indoors, surface, underground) and the value would be the map itself, but this wouldn't let me do multiple string assignments to each value.

Is there a way I can keep a list of arrays and have several strings describing each one? For example, if I want to affect all maps which are indoors, it'd be great if I could just look up everything that fits that description. I need to pass this list around through many functions too and I'm trying to move away from using global to do it.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
You can use a dictionary as a "value-bag".

Python code:
map_01 = [ ... ]
map_02 = [ ... ]

maps = [
    { "type": "outdoor", "id": "home", "map": map_01, },
    { "type": "outdoor", "id": "farmland", "map": map_02, },
    # more as needed
]

reading
Jul 27, 2013

Suspicious Dish posted:

You can use a dictionary as a "value-bag".

Python code:
map_01 = [ ... ]
map_02 = [ ... ]

maps = [
    { "type": "outdoor", "id": "home", "map": map_01, },
    { "type": "outdoor", "id": "farmland", "map": map_02, },
    # more as needed
]

Is that a list-of-dicts?

ShadowHawk
Jun 25, 2000

CERTIFIED PRE OWNED TESLA OWNER

reading posted:

Is that a list-of-dicts?
Yes.

reading
Jul 27, 2013
I think I might just go with multiple space-delimited words in the key and just do string searches/string comprehension on them as needed, so that I can stick with a very basic dict.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

reading posted:

I think I might just go with multiple space-delimited words in the key and just do string searches/string comprehension on them as needed, so that I can stick with a very basic dict.

This....

I don't know what to say, really.

EAT THE EGGS RICOLA
May 29, 2008

You're going to do what now?

reading
Jul 27, 2013
Sorry I mean something like: { "outdoors surface": map1} and then search for all keys that contain the word "outdoors" for example.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

Why would you want to do that though? Suspicious D's version basically has a set of clear fields you can use for whatever lookups you like, you're just smooshing them all into a string you'll have to take apart and analyse later. Naming complexity and efficiency aside, is this actually making your life any easier? Are you just uneasy about nesting dicts? Think of them as records in a table, if you like

e- if you wanted a list of outdoor maps you could just do [map['map'] for map in maps if map['type'] == 'outdoors'] and you're done. I don't think it would be much different for a string, just slower and more prone to issues (like what if you want to tag several attributes with 'large' or 'small'? Do you prefix with the attribute so you know what 'small' in the string actually refers to?)

baka kaba fucked around with this message at 02:36 on Jan 2, 2015

Jewel
May 2, 2009

reading posted:

Sorry I mean something like: { "outdoors surface": map1} and then search for all keys that contain the word "outdoors" for example.

Python code:
maps = [
    { "type": "outdoor", "id": "home", "map": map_01, },
    { "type": "outdoor", "id": "farmland", "map": map_02, },
    { "type": "indoor", "id":  "home_indoor", "map": map_03, },
    { "type": "indoor", "id":  "restraunt", "map": map_04, }
]

allOutdoor = filter(lambda x: x["type"] == "outdoor", maps)

# alternative:
allOutdoor = [x for x in maps if x["type"] == "outdoor"] #look into list comprehension

for map in allOutdoor:
	print map #or you can go map["id"] to find the name of each map you found

#prints:
#> {'map': [...], 'type': 'outdoor', 'id': 'home'}
#> {'map': [...], 'type': 'outdoor', 'id': 'farmland'}
Also because filter takes a function, if you want to make it easier on yourself to read it, you can do something like this

Python code:
def isOutdoor(map):
	return map["type"] == "outdoor" # returns true if outdoors
	
allOutdoor = filter(isOutdoor, maps)

SurgicalOntologist
Jun 17, 2004

Not to mention that with a dict key that is just a bunch of keywords you are ensuring that you are never going to use the dict for key-based lookup, thus defeating the purpose of using a dict at all. So if you really wanted to use a keywords approach, instead use (name, keywords, map) tuples. And make keywords a set or list of strings.

But really the list-of-dicts suggestion is the obvious answer here. The above is much more explicit than
Python code:
def is_outdoor(map):
    return 'outdoor' in map[1]
which is what you'd end up with using a sane keywords-based approach.

SurgicalOntologist fucked around with this message at 03:35 on Jan 2, 2015

QuarkJets
Sep 8, 2008

It's definitely way more efficient to use multiple dictionary entries instead of a single long string that you then have to parse. Don't do the string parsing thing, that's going to be slow as poo poo

You could also use a class

Python code:
class GameMap(object):
    def __init__(self, type, id, map):
        self.type = type
        self.id = id
        self.map = map

maps = [
    GameMap("outdoor", "home" map_01),
    GameMap("outdoor", "farmland", map_02),
    GameMap("indoor", "home_indoor", map_03),
    GameMap("indoor", "restaurant", map_04)
]

allOutdoor = filter(lambda x: x.type == "outdoor", maps)

# alternative:
allOutdoor = [x for x in maps if x.type == "outdoor"] #look into list comprehension

for map in allOutdoor:
    print map #or you can go map["id"] to find the name of each map you found
Technically, classes are just dictionaries, but a class implementation can be a little cleaner. And if you need to add a method for dealing with some of the internal data, then that's really easy

reading
Jul 27, 2013

QuarkJets posted:

It's definitely way more efficient to use multiple dictionary entries instead of a single long string that you then have to parse. Don't do the string parsing thing, that's going to be slow as poo poo

You could also use a class

Python code:
class GameMap(object):
    def __init__(self, type, id, map):
        self.type = type
        self.id = id
        self.map = map

maps = [
    GameMap("outdoor", "home" map_01),
    GameMap("outdoor", "farmland", map_02),
    GameMap("indoor", "home_indoor", map_03),
    GameMap("indoor", "restaurant", map_04)
]

allOutdoor = filter(lambda x: x.type == "outdoor", maps)

# alternative:
allOutdoor = [x for x in maps if x.type == "outdoor"] #look into list comprehension

for map in allOutdoor:
    print map #or you can go map["id"] to find the name of each map you found
Technically, classes are just dictionaries, but a class implementation can be a little cleaner. And if you need to add a method for dealing with some of the internal data, then that's really easy

I think I will go this route. I was initially confused about how an object might absorb and index all the maps, but making a list of objects seems clear. I was thinking about it backwards.

Edit: quick question, is "class MyClass(object): " and "class MyClass: " just a notation thing, or does including (object) matter somewhere?

Thanks everyone for your help and code examples.

reading fucked around with this message at 07:34 on Jan 2, 2015

'ST
Jul 24, 2003

"The world has nothing to fear from military ambition in our Government."

reading posted:

Edit: quick question, is "class MyClass(object): " and "class MyClass: " just a notation thing, or does including (object) matter somewhere?
In Python 2.x, you want to use "class MyClass(object)." In Python 3.x, it's fine to use "class MyClass."

The reasoning is historical. If you proceed rigidly by the above approach, you won't run into problems. You should always use new-style classes in new code since Python 2.3.

The basic reason is that Python classes before 2.3 were a lot different and weren't treated like first-class objects. If you use the new-style classes in Python 2.x by inheriting from object, classes can be treated properly as types and objects can be identified as instances of their classes.

Python 3.x thankfully got rid of the old-style classes, so everything inherits from object by default.

You can read up on new-style vs. old-style classes if you're particularly interested. Here is some quick code from 2.7 that gives hints about how these types of classes differ.

Python code:
Python 2.7.2 (default, Jul 20 2011, 02:32:18)
[GCC 4.2.1 (LLVM, Emscripten 1.5, Empythoned)] on linux2
   class NewStyle(object): 
..   def __init__(self, a): 
..     self.a = a 
..     
   class OldStyle: 
..   def __init__(self, a): 
..     self.a = a 
..     
   old_instance = OldStyle(5)
   new_instance = NewStyle(5)
   type(old_instance)
=> <type 'instance'>
   type(new_instance)
=> <class '__main__.NewStyle'>
   type(OldStyle)
=> <type 'classobj'>
   type(NewStyle)
=> <type 'type'>

reading
Jul 27, 2013

QuarkJets posted:

It's definitely way more efficient to use multiple dictionary entries instead of a single long string that you then have to parse. Don't do the string parsing thing, that's going to be slow as poo poo

You could also use a class

Python code:
class GameMap(object):
    def __init__(self, type, id, map):
        self.type = type
        self.id = id
        self.map = map

maps = [
    GameMap("outdoor", "home" map_01),
    GameMap("outdoor", "farmland", map_02),
    GameMap("indoor", "home_indoor", map_03),
    GameMap("indoor", "restaurant", map_04)
]

allOutdoor = filter(lambda x: x.type == "outdoor", maps)

# alternative:
allOutdoor = [x for x in maps if x.type == "outdoor"] #look into list comprehension

for map in allOutdoor:
    print map #or you can go map["id"] to find the name of each map you found
Technically, classes are just dictionaries, but a class implementation can be a little cleaner. And if you need to add a method for dealing with some of the internal data, then that's really easy

I've run in to a problem with implementing this. Since the maps are 2D arrays (and I obtain information about each square with, for example, "map[x][y].info") I don't know how to create a __getitem__ method in the GameMap class which will allow this kind of iteration. I keep getting TypeError: "GameMap" object does not support indexing.

SurgicalOntologist
Jun 17, 2004

Python code:
def __getitem__(self, ix):
    return self.map[ix]
should work.

Edit: you may want to use self._map instead of self.map. The leading underscore is convention for "outside of the class, you don't need to know this exists". So if you want users of GameMap (i.e., yourself, in other code) to interact with the object directly instead of accessing its map attribute all the time, that would be signified by a leading underscore on the attribute name.

SurgicalOntologist fucked around with this message at 00:42 on Jan 3, 2015

QuarkJets
Sep 8, 2008

reading posted:

I've run in to a problem with implementing this. Since the maps are 2D arrays (and I obtain information about each square with, for example, "map[x][y].info") I don't know how to create a __getitem__ method in the GameMap class which will allow this kind of iteration. I keep getting TypeError: "GameMap" object does not support indexing.

It sounds like you're trying to index into a GameMap object directly instead of accessing its map attribute. Try map.map[x][y].info, or define the __getitem__ method like as was described above

Adbot
ADBOT LOVES YOU

onionradish
Jul 6, 2006

That's spicy.
Unrelated to your issue, but something to be aware of because things like this can really bite you in the butt later:

If you use "map" as a variable name, you are overwriting the built-in Python function "map" with your data. You variable will work, but the function won't, and it won't be obvious why code that uses that function looks like it should be working but isn't.

You're probably not using the "map" function in your script and may not need to, but it's a good habit to avoid using Python reserved words as variables. Otherwise, it's really easy to accidentally write things like "list = [1,2,3]" or "type = 'mountains'" or "range = 10".

You *can* use reserved words as class attribute names like "self.map[x][y]" in the example from SurgicalOntologist below, because they're attached to the object.

PyCharm was invaluable when I was learning because it flagged that kind of stuff.

  • Locked thread