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
Dominoes
Sep 20, 2007

nvm

Adbot
ADBOT LOVES YOU

tbp
Mar 1, 2008

DU WIRST NIEMALS ALLEINE MARSCHIEREN
I'm using python (w/ pygal) to make a few charts based on soccer player stats. It's easy enough when I hardcode the stats to the chart generated, but i'm unsure of how to make it so that I can have the user type in the name of the player they want to use the data stored in the variable to make the charts. This is how I have it set up:

code:
####Data
RonaldoGoalsName = ('Ronaldo Goals')
RonaldoGoalsData = ([3, 4, 5, 9, 17, 31, 18, 26, 40, 46, 34, 31, 25])
RonaldoAppearancesName = ('Ronaldo Appearances')
RonaldoAppearancesData = ([25, 29, 33, 33, 34, 34, 33, 29, 34, 38, 34, 30, 14])
MessiGoalsName = ('Messi Goals')
MessiGoalsData = ([None, None, 1, 6, 14, 10, 23, 34, 31, 50, 46, 28, 13])
MessiAppearancesName = ('Messi Appearances')
MessiAppearancesData = ([None, None, 7, 17, 26, 28, 31, 35, 33, 37, 32, 31, 14])
SuarezGoalsName = ('Suarez Goals')
SuarezGoalsData = ([None, None, None, None, 10, 10, 17, 22, 35, 11, 11, 23, 31])
SuarezAppearancesName = ('Suarez Appearances')
SuarezAppearancesData = ([None, None, None, None, 27, 29, 33, 31, 33, 26, 31, 33, 7])

####Custom chart
def customplayer_make_line_chart():
    customplayer_line = pygal.Line()
    customplayer.title = "Player Comparison"
    customplayer.x_labels = map(str, range(2002, 2015))
    customplayer.add()
    customplayer.add()
    customplayer.add()
    customplayer.add()

##GUI
root = Tk()
root.title("Ronaldo vs Messi Graph Generator")
root.geometry("600x350")

playerentry = Entry(root)
playerentry.pack(pady=10)

playerentry2 = Entry(root)
playerentry2.pack(pady=10)
root.mainloop()
So ideally what I'd want to do is use whatever it entered in the playerentry Entry boxes as the name and basically get the right variables based on a shortname.

I figure I'd have to make classes for this? But the syntax of it all seems a bit lost on me, and I'm unsure of actually how to put it int he code

SurgicalOntologist
Jun 17, 2004

Whenever you find yourself wanting to use different variables based on their name, the answer is usually a dictionary.

In this case you'd be best served with something designed for data, like pandas, but as an exercise maybe just start with dictionaries. I'll suggest something like

Python code:
data = {
    'Ronaldo': {
        'appearances':
            [25, 29, 33, 33, 34, 34, 33, 29, 34, 38, 34, 30, 14],
        'goals':
            [3, 4, 5, 9, 17, 31, 18, 26, 40, 46, 34, 31, 25],
    },
    ...
}
From there you should find it relatively easy to choose the data based on the user selection.

Cingulate
Oct 23, 2012

by Fluffdaddy
Is there a simple explanation (rule) for why (or when) in such contexts, dicts are preferable over objects (ie., dict[key] vs object.attribute)?

tbp
Mar 1, 2008

DU WIRST NIEMALS ALLEINE MARSCHIEREN

SurgicalOntologist posted:

Whenever you find yourself wanting to use different variables based on their name, the answer is usually a dictionary.

In this case you'd be best served with something designed for data, like pandas, but as an exercise maybe just start with dictionaries. I'll suggest something like

Python code:
data = {
    'Ronaldo': {
        'appearances':
            [25, 29, 33, 33, 34, 34, 33, 29, 34, 38, 34, 30, 14],
        'goals':
            [3, 4, 5, 9, 17, 31, 18, 26, 40, 46, 34, 31, 25],
    },
    ...
}
From there you should find it relatively easy to choose the data based on the user selection.

Ah, thank you. This does look like a much more logical way of arranging this, especially because then it becomes far more scale-able. I'll be able to periodically add more "stats" into a player's data set if I want.

I don't have the chance to get into IDLE at the moment but I am assuming then the way I would get the variable I need would be something like

customplayer.add(%playerentry.get['goals'],%playerentry.get[appearances])

Does this seem right?

Thanks again for the help

Dominoes
Sep 20, 2007

Cingulate posted:

Is there a simple explanation (rule) for why (or when) in such contexts, dicts are preferable over objects (ie., dict[key] vs object.attribute)?
Use a dict unless you need to pass the data through multiple functions, or want to import it into other modules.

Dominoes fucked around with this message at 20:49 on Dec 18, 2014

SurgicalOntologist
Jun 17, 2004

tbp posted:

Ah, thank you. This does look like a much more logical way of arranging this, especially because then it becomes far more scale-able. I'll be able to periodically add more "stats" into a player's data set if I want.

I don't have the chance to get into IDLE at the moment but I am assuming then the way I would get the variable I need would be something like
code:
customplayer.add(%playerentry.get['goals'],%playerentry.get[appearances])
Does this seem right?

Thanks again for the help

No, I'm not really sure what's going on there. The % at least will give you a syntax error.

I'm not very familiar with whatever UI framework you're using. But I'd guess get is a function in which case you need to use parentheses, not square brackets. But in general what you want is something like

code:
name = 'Ronaldo'
goals = data[name]['goals']
appearances = data[name]['appearances']
That's how you get the data out at least. The rest of the code depends on what you're doing with it. (Just to clear you probably won't have any of those exact lines. Replace the first line with however you get user entry, and then use the part to the right of the = sign in 2-3 wherever you need to put the data).

Cingulate posted:

Is there a simple explanation (rule) for why (or when) in such contexts, dicts are preferable over objects (ie., dict[key] vs object.attribute)?

Like Dominoes said, make a class if you need state and behavior (i.e. functions that all need that same bunch of data). So if you find yourself passing the same dict or set of data in general to every function that's a sign you need a class.

The other reason to prefer dicts, though, is if you need to get access based on a string that you only have in a variable. In this case you can't do attribute syntax (i.e. you can't do data.Ronaldo if you only have the string Ronaldo via the variable name). So in that example, the equivalent of data[name] with an object would have to be getattr(data, name) at which point I'd rather have a dict.

It's not as bad as having information you need to know at runtime in your variable names, but I wouldn't want that in my attribute names either.

SurgicalOntologist fucked around with this message at 22:25 on Dec 18, 2014

Master_Odin
Apr 15, 2010

My spear never misses its mark...

ladies
So I have the following issue when running pylint (which is through a custom runner, but I do not think the runner has any here?). I have the following set-up:
  • tests/
    • board_tester.py
    • test_boards.py
  • board.py
  • pylint_runner.py

with board_tester.py containing the line:
code:
import test.test_boards as test_boards
which gives me a bunch of pre-built boards to use to save me effort of setting them up.

however, when I run my pylint_runner.py (which is equivalent to running "pylint tests/board_tester.py" and so on), I get the following error on board_tester.py:

quote:

************* Module board_tester
E: 8, 0: No name 'test_boards' in module 'setuptools.tests' (no-name-in-module)
F: 8, 0: Unable to import 'tests.test_boards' (import-error)

I'd rather not add ignores to that specific line, but I have no idea on the error (and it's not like I can run the file directly anyway as I just get an import error on Board (though nosetests works fine)

Is there a better setup for python files when building a game (Connect 4 in this case) that I'm not following?

Master_Odin fucked around with this message at 06:15 on Dec 19, 2014

FoiledAgain
May 6, 2007

tbp posted:

So ideally what I'd want to do is use whatever it entered in the playerentry Entry boxes as the name and basically get the right variables based on a shortname.

You should learn about "tk variables" (just google it, you probably want the effbot site, it's very good for tk material). You attach a textvariable to your Entry widget so that you can look up the contents of the widget from anywhere. Something like this:

code:

from tkinter import *

root = Tk()
selected_player = StringVar()

main_window = Toplevel(root)
player_frame = LabelFrame(main_window, text='Enter a player name')
player_entry = Entry(player_frame, textvariable=selected_player)
player_entry.grid()
ok = Button(player_frame, text='Select', command=choose_player)
ok.grid()
player_frame.grid()

root.mainloop()

def choose_player():
    player_name = selected_player.get() #this is where tk variables come in handy
    #add code to display player stats here
    if player_name == 'famous_guy_1':
        #do some stuff
    elif player_name == 'famous_guy_2':
        #do some stuff
    

FoiledAgain fucked around with this message at 07:08 on Dec 19, 2014

tbp
Mar 1, 2008

DU WIRST NIEMALS ALLEINE MARSCHIEREN

FoiledAgain posted:

You should learn about "tk variables" (just google it, you probably want the effbot site, it's very good for tk material). You attach a textvariable to your Entry widget so that you can look up the contents of the widget from anywhere. Something like this:

code:

from tkinter import *

root = Tk()
selected_player = StringVar()

main_window = Toplevel(root)
player_frame = LabelFrame(main_window, text='Enter a player name')
player_entry = Entry(player_frame, textvariable=selected_player)
player_entry.grid()
ok = Button(player_frame, text='Select', command=choose_player)
ok.grid()
player_frame.grid()

root.mainloop()

def choose_player():
    player_name = selected_player.get() #this is where tk variables come in handy
    #add code to display player stats here
    if player_name == 'famous_guy_1':
        #do some stuff
    elif player_name == 'famous_guy_2':
        #do some stuff
    

Ah, this is incredible, thank you. Syntax kicks my rear end, I feel like I have the idea of what to do down but can't figure out how to "translate" it very well yet.. if that makes sense

SurgicalOntologist
Jun 17, 2004


Not sure if this is the issue, but you could try putting a blank __init.py__ file in tests/.

Master_Odin
Apr 15, 2010

My spear never misses its mark...

ladies

SurgicalOntologist posted:

Not sure if this is the issue, but you could try putting a blank __init.py__ file in tests/.
That did it, thanks! Still sort of makes me wonder if this is the proper way to setup a tests suite (or just not run my test suite through pylint?!) but at least for now, everything builds properly v:v:v

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

Hi I'm an idiot, can someone tell me how in the hell you add a local library to a project in PyCharm? Explain it like half my brain is missing, because it feels like it is after the past hour (for some reason this is an amazing fertile ground for spam websites scraping Stack Exchange)

I've installed the PyCrypto binaries since I don't have a C compiler installed, so that's living in Python34\Lib\site-packages right now. My project is set up with a VirtualEnv. I can install packages from the Project Interpreter screen, which is nice and all since they come from the internet, but I need to add this local package instead, and I can't see any way to do that.

Closest I've got from randomly clicking on things (which is where I'm at now) is adding site-packages as a Content Root which at least makes it appear under External Libraries. Is this the right way to do things? Code completion isn't working at all, is that a separate issue or have I done this wrong?

QuarkJets
Sep 8, 2008

baka kaba posted:

Hi I'm an idiot, can someone tell me how in the hell you add a local library to a project in PyCharm? Explain it like half my brain is missing, because it feels like it is after the past hour (for some reason this is an amazing fertile ground for spam websites scraping Stack Exchange)

I've installed the PyCrypto binaries since I don't have a C compiler installed, so that's living in Python34\Lib\site-packages right now. My project is set up with a VirtualEnv. I can install packages from the Project Interpreter screen, which is nice and all since they come from the internet, but I need to add this local package instead, and I can't see any way to do that.

Closest I've got from randomly clicking on things (which is where I'm at now) is adding site-packages as a Content Root which at least makes it appear under External Libraries. Is this the right way to do things? Code completion isn't working at all, is that a separate issue or have I done this wrong?

http://stackoverflow.com/questions/19885821/how-do-i-import-modules-in-pycharm

Basically yes, you can just set paths in PyCharm and that's acceptable (in a Windows environment)

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

Ok, I tried that one earlier but I think it failed because I added the Crypto folder and not the one above that. Is this basically the same as adding a Content Root? I'd test it out but now I've removed those paths it's still showing up in External Libraries. It sure is a mystery!

e- scratch that, I've somehow got it showing Unresolved Reference errors on imports now when the code executes fine. If I change the import and drop the Crypto package prefix the inspection errors disappear, but the program fails because now it can't find the module :psyduck:

baka kaba fucked around with this message at 00:45 on Dec 21, 2014

reading
Jul 27, 2013
I'm going through the libtcod tutorial for making a roguelike at http://www.roguebasin.com/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_13_code and I'm really confused about this stuff:

code:
class Object:
    #this is a generic object: the player, a monster, an item, the stairs...
    #it's always represented by a character on screen.
    def __init__(self, x, y, char, name, color, blocks=False, always_visible=False, fighter=None, ai=None, item=None, equipment=None):
        self.x = x
        self.y = y
        self.char = char
        self.name = name
        self.color = color
        self.blocks = blocks
        self.always_visible = always_visible
        self.fighter = fighter
        if self.fighter:  #let the fighter component know who owns it
            self.fighter.owner = self
 
        self.ai = ai
        if self.ai:  #let the AI component know who owns it
            self.ai.owner = self
 
        self.item = item
        if self.item:  #let the Item component know who owns it
            self.item.owner = self
 
        self.equipment = equipment
        if self.equipment:  #let the Equipment component know who owns it
            self.equipment.owner = self
 
            #there must be an Item component for the Equipment component to work properly
            self.item = Item()
            self.item.owner = self
class Fighter, class Item, class Equipment, and several AI classes are defined elsewhere.

I understand "self" in python, and I'm slowly comprehending the ability to assign objects to other objects which is done frequently in this tutorial, but there are two things I need help understanding:

"self.equipment.owner = self" what exactly is this about? Who owns what?

"self.item = item" versus "self.item = Item()" what's the difference here? What does it mean to invoke a class like a function with "()" ?

Finally, I do not understand the whole self.equipment section. I understand that logically an Equipment must also be an Item, but the three lines of code
code:
self.equipment.owner = self
 
#there must be an Item component for the Equipment component to work properly
self.item = Item()
self.item.owner = self
are really confusing to me. I would appreciate any help from object oriented gurus, I'm mostly an embedded C programmer.

salisbury shake
Dec 27, 2011

reading posted:

I'm going through the libtcod tutorial for making a roguelike at http://www.roguebasin.com/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_13_code and I'm really confused about this stuff:

code:
class Object:
    #this is a generic object: the player, a monster, an item, the stairs...
    #it's always represented by a character on screen.
    def __init__(self, x, y, char, name, color, blocks=False, always_visible=False, fighter=None, ai=None, item=None, equipment=None):
        self.x = x
        self.y = y
        self.char = char
        self.name = name
        self.color = color
        self.blocks = blocks
        self.always_visible = always_visible
        self.fighter = fighter
        if self.fighter:  #let the fighter component know who owns it
            self.fighter.owner = self
 
        self.ai = ai
        if self.ai:  #let the AI component know who owns it
            self.ai.owner = self
 
        self.item = item
        if self.item:  #let the Item component know who owns it
            self.item.owner = self
 
        self.equipment = equipment
        if self.equipment:  #let the Equipment component know who owns it
            self.equipment.owner = self
 
            #there must be an Item component for the Equipment component to work properly
            self.item = Item()
            self.item.owner = self
class Fighter, class Item, class Equipment, and several AI classes are defined elsewhere.

I understand "self" in python, and I'm slowly comprehending the ability to assign objects to other objects which is done frequently in this tutorial, but there are two things I need help understanding:

"self.equipment.owner = self" what exactly is this about? Who owns what?

"self.item = item" versus "self.item = Item()" what's the difference here? What does it mean to invoke a class like a function with "()" ?

Finally, I do not understand the whole self.equipment section. I understand that logically an Equipment must also be an Item, but the three lines of code
code:
self.equipment.owner = self
 
#there must be an Item component for the Equipment component to work properly
self.item = Item()
self.item.owner = self
are really confusing to me. I would appreciate any help from object oriented gurus, I'm mostly an embedded C programmer.

You're reading over the code for the class that an instance will be made of. Think of every self as a reference to 'this one instance'

When you see:
code:
some_item = Item()
a, b, c = Item(), Item(), Item()
a.owner = 'Abc'
b.owner = 'Def'
etc
In this case, object and Object are two different things. When I use the lowercase I mean a Python or OO style object, and with the uppercase I mean your class.

You are constructing an object as defined by the class Item, as seen in line 1 by calling the classname with parentheses. The class itself is an object, but an object from which copies, or instances can be made from by calling it with parentheses. You can have many instances of a class, by this I mean you can have many Items that have different (or the same) attributes since they exist separately in memory.

To the some_item object, when one of its instance methods is called:
code:
def something(self, equipment):
        self.equipment = equipment
        if self.equipment:  #let the Equipment component know who owns it
            self.equipment.owner = self
self is a reference to the object some_item, and is pretty much the same as:
code:
        some_item.equipment = equipment
        if some_item.equipment:  #let the Equipment component know who owns it
            some_item.equipment.owner = some_item
And the same holds true for a, b, c:
code:
a.equipment = equipment
etc
To answer your question as to who owns what: the instance of Object has an attribute called equipment. A pointer to the instance of Object in memory is assigned to Equipment's owner attribute.

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord
It may just be me but self.equipment.owner = self looks kind of goofy.

BeefofAges
Jun 5, 2004

Cry 'Havoc!', and let slip the cows of war.

Yeah I've never seen that sort of thing before.

Lister_of_smeg
May 25, 2005
I'm hoping someone here with Python GUI experience can point me in the right direction. We've got some Python classes that are used to represent a tree of objects. The tree is loaded in from another program and is variable in size (ranging from a single element to hundreds).

We've developed various command line tools to perform various operations on the tree but we're lacking an easy way to get a visual representation of it. That's where some kind of GUI tool comes in. I want something that can represent the tree, initially statically but eventually dynamically (expanding/collapsing branches, etc.).

I've been looking at Tkinter and think it could probably do what I need but am open to anything that works on Linux. I have no experience of GUI development though (all CLI tools) so would appreciate any advice on what tools to use, good learning resources, etc. Ideally I'd like to just link our existing classes up to a GUI framework and have it all automagically happen from there. I accept that I'll probably have to provide the automagic.

candide
Jun 16, 2002

The Tipping Point
PyQt and their model-view framework may be an option. One approach is to load your data in one of Qt's model classes and then use one of the view classes to point to the model and automagically view your data.

You could possibly derive from QAbstractItemModel to load your data and QTreeView to display it with expandable/collapsible options, sorting, etc.

Heavy_D
Feb 16, 2002

"rararararara" contains the meaning of everything, kept in simple rectangular structures

reading posted:

I'm going through the libtcod tutorial for making a roguelike at http://www.roguebasin.com/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_13_code and I'm really confused about this stuff:

"self.equipment.owner = self" what exactly is this about? Who owns what?
Here we have a chain of properties, each of which is talking about an object:
  • self is the current entity
  • self.equipment is a property of the current object, which stores the equipment object
  • self.equipment.owner is defining a property on the equipment object
  • self.equipment.owner = self is setting the property on the equipment object to point at the original object
The result is a small loop. The self object can find the equipment object by looking at the "equipment" property, and the equipment object can locate the self object by looking at the "owner" propertry.

quote:

"self.item = item" versus "self.item = Item()" what's the difference here? What does it mean to invoke a class like a function with "()" ?

In reverse order: Item() makes a new object of the Item class. The lowercase item is a parameter to the _init_ function, so the person calling our code may have a pre-made Item they would like to send for us to use.

Hopefully that should clarify the self.equipment section, as it's just these two tricks happening twice in a row.

KICK BAMA KICK
Mar 2, 2009

This sounded familiar so I actually went back a ways in this thread to confirm, and this is the the same tutorial that brought someone else here trying to debug an odd error message because the tutorial was using some ill-advised practices with global variables and shadowing built-in names. I'm again thinking this just might not be a very good tutorial.

I don't love defining a class with the name Object (mostly if that's Python 2 but really even if it's not). In Python 2 object is the name of the built-in class that pretty much all user-defined classes should subclass because reasons. Defining your own class Object invites typos and misreading in Python 2, and even if this is a Python 3 tutorial where object is no longer necessary it's still defined and could easily confuse a reader with a Python 2 background. Also in any language Object would be a completely nondescript name that fails to tell me anything about the behavior this class encapsulates. The comment
Python code:
    #this is a generic object: the player, a monster, an item, the stairs...
    #it's always represented by a character on screen
seems to imply it's purpose is to collect the state and behavior common to anything with a physical location in this game world. But parameters like fighter, ai, item, equipment look like they don't have anything to do with that idea and now we're just bundling up a shitload of conceptually unrelated functionality into one thing.

Really the most striking error in that tutorial is the format of the above comment (and the mistake is repeated throughout) -- class-level docstrings should always be in triple quotes: """This is a generic object...""". Maybe that's a really minor nitpickbut it jumps out at me as something that absolutely no one who knows the first thing about Python conventions would ever do. Read any Python code, take any tutorials that were written by someone more experienced than this, interact with other Python codes, somewhere along the way you're going to learn not to do that. And while it doesn't actually impact the execution of the program, it's not purely a point of style. Python's introspection features actually recognize a triple-quoted string literal immediately following a class declaration as the docstring for that class; a # comment won't be noticed.
Python code:
>>> class Wrong:
	# This is the wrong way to write a docstring
	pass

>>> class Right:
	"""This is correct."""
	pass

>>> Right.__doc__
'This is correct.'
>>> Wrong.__doc__
>>>
I imagine a lot of IDEs and other tools rely on the same convention. Maybe this tutorial is OK for teaching roguelike design concepts, I haven't looked that hard, but I think it's pretty lovely for teaching Python.

Lister_of_smeg
May 25, 2005

henn and potion posted:

PyQt and their model-view framework may be an option. One approach is to load your data in one of Qt's model classes and then use one of the view classes to point to the model and automagically view your data.

You could possibly derive from QAbstractItemModel to load your data and QTreeView to display it with expandable/collapsible options, sorting, etc.

That sounds like it could be perfect. Thanks!

ShadowHawk
Jun 25, 2000

CERTIFIED PRE OWNED TESLA OWNER

Symbolic Butt posted:

It may just be me but self.equipment.owner = self looks kind of goofy.

BeefofAges posted:

Yeah I've never seen that sort of thing before.
I believe it's a symptom of not fully separating what each class does, or having the wrong ownership of methods that interact between them.

Say you have a class for countries, and a class for people. One reasonable way to do it is to have countries have a variable holding the instances of the people class. Now say you want to have a "birth" method to create a new person and have that person know who its mother is.

If you put the logic in the country class (country.new_person(mother)), a single method can neatly create a new person inside the country, reference the mother, and then add it to the population set.

If you put the logic in the person class and have the mother invoke it (person.give_birth()), then each person class needs to know what country it's in so that it can then adjust data belonging to the country class. It's not far from there to asking for a circular reference in the __init__ function.

good jovi
Dec 11, 2000

'm pro-dickgirl, and I VOTE!

Symbolic Butt posted:

It may just be me but self.equipment.owner = self looks kind of goofy.

This smells like someone trying to build a class structure that directly mirrors their database relationships.

reading
Jul 27, 2013

Heavy_D posted:

Here we have a chain of properties, each of which is talking about an object:
  • self is the current entity
  • self.equipment is a property of the current object, which stores the equipment object
  • self.equipment.owner is defining a property on the equipment object
  • self.equipment.owner = self is setting the property on the equipment object to point at the original object
The result is a small loop. The self object can find the equipment object by looking at the "equipment" property, and the equipment object can locate the self object by looking at the "owner" propertry.


In reverse order: Item() makes a new object of the Item class. The lowercase item is a parameter to the _init_ function, so the person calling our code may have a pre-made Item they would like to send for us to use.

Hopefully that should clarify the self.equipment section, as it's just these two tricks happening twice in a row.

Won't this cause a problem since an Object instance might be created with the "item=blahblah" parameter already filled, but then in the lines
code:
...
if self.equipment:  #let the Equipment component know who owns it
            self.equipment.owner = self
 
            #there must be an Item component for the Equipment component to work properly
            self.item = Item()
...
a second Item instance is being created? So now this instance of Object has two Item instances attached to it?

Heavy_D
Feb 16, 2002

"rararararara" contains the meaning of everything, kept in simple rectangular structures
No, the first one gets replaced by the second one. It's hard to believe that's a design choice instead of a bug, I agree with the other posters that this code seems like a bit of a mess...

Nippashish
Nov 2, 2005

Let me see you dance!
I went through some of the libcotd tutorials a few years ago and can confirm that they are a disaster zone of bad coding choices.

FoiledAgain
May 6, 2007

Symbolic Butt posted:

It may just be me but self.equipment.owner = self looks kind of goofy.

ShadowHawk posted:

I believe it's a symptom of not fully separating what each class does, or having the wrong ownership of methods that interact between them.

Just for the sake of discussion, let's imagine that party members can lend each other equipment, but items have special properties when equipped on the original owner. In this case, wouldn't it be useful to keep track which Object instance is the owner? And supposing the answer is 'yes', would there be a better way?

QuarkJets
Sep 8, 2008

FoiledAgain posted:

Just for the sake of discussion, let's imagine that party members can lend each other equipment, but items have special properties when equipped on the original owner. In this case, wouldn't it be useful to keep track which Object instance is the owner? And supposing the answer is 'yes', would there be a better way?

You could define a setOwner method that handles the setting of parameters, and require that an owner instance be passed to the method. If the owner is self, some parameters would be modified in a different way. This would also enable you to modify object parameters based on things other than the identity of the owner; for example, Knight Gregory's sword could have +10 damage if he's the owner, +5 damage if any other Knight is the owner (you should be able to check this via the owner instance that was passed), or no change if anyone else is the owner. In this scenario, there's no need to keep track of the current owner, or any owner at all really (unless you have a good reason for an item to be continuously aware of its owner).

In the case where we do keep track of the owner, I don't see any advantage. Is the sword checking the name of its owner every time that it's used and then adjusting parameters on a per-use basis? That seems unnecessary. Maybe you need some character attributes when calculating damage, but I think that it would make more sense to attach that calculation to the character rather than the weapon (the character should have a reference to the weapon, so accessing the weapon's damage is straightforward anyway)

So basically yes, you could keep track of the owner, but I am having trouble imagining a good reason to do this. Maybe if you built a game about sentient items that control their owners?

QuarkJets fucked around with this message at 00:16 on Dec 22, 2014

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

good jovi posted:

This smells like someone trying to build a class structure that directly mirrors their database relationships.

It's more like somebody trying to build Python bindings around a horrible C library that was extracted out of Hack.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
I'm coming back to a personal project that I set aside a while ago. The project involves using PLY to create a parser for a domain specific language. There is a long and detailed help file, which is great, but one thing that strikes me as weird is this:

quote:

Internally, lex.py uses the re module to do its patten matching. When building the master regular expression, rules are added in the following order:

All tokens defined by functions are added in the same order as they appear in the lexer file.
Tokens defined by strings are added next by sorting them in order of decreasing regular expression length (longer expressions are added first).

This business of treating functions based on the order they were defined - is that something that is used by other Python projects? Is it something that is guaranteed to not be broken by future versions of Python? It seems like a funny thing to rely on.

The way you create a lexer (by calling a function in the module rather than by calling Lexer()) is awkward too, as I want to subclass the Lexer class to tweak its behaviour but it's set up in such a way that it's hard to know how to do that. Just having a wrapper class that contains a Lexer is not a perfect solution, as the token parameters to so-called "rule" functions/methods contain a reference to the Lexer object.

Aaronicon
Oct 2, 2010

A BLOO BLOO ANYONE I DISAGREE WITH IS A "BAD PERSON" WHO DESERVES TO DIE PLEEEASE DONT FALL ALL OVER YOURSELF WHITEWASHING THEM A BLOO BLOO
Speaking of that terrible libtcodpy tutorial, is there any practical difference between going

Python code:
ClassName(BaseClass):

    def __init__(self):
        super(ClassName, self).__init__()
vs

Python code:
ClassName(BaseClass):

    def __init__(self):
        BaseClass.__init__(self)
I believe they both accomplish the same thing but the latter seems a lot cleaner and 'pythonic' to me. The super() syntax doesn't feel nice to me, for lack of any other actual reason. I mean arguably the second method means that you have to change the name of the function should you ever change the name of the BaseClass, but we live in the year 2014 and if you don't have an IDE with find/replace I don't know what to tell you.

Aaronicon fucked around with this message at 11:17 on Dec 22, 2014

syncathetic
Oct 21, 2010
There isn't any practical difference most of the time. It can make a difference when using multiple inheritance

Python code:
class A(object):
    def __init__(self):
        super(A, self).__init__()
        print "A"

class B(A):
    def __init__(self):
        super(B, self).__init__()
        print "B"

class C(A):
    def __init__(self):
        super(C, self).__init__()
        print "C"

class D(B, C):
    def __init__(self):
        super(D, self).__init__()
        print "D"

D()
code:
A
C
B
D
Python code:
class A(object):
    def __init__(self):
        object.__init__(self)
        print "A"

class B(A):
    def __init__(self):
        A.__init__(self)
        print "B"

class C(A):
    def __init__(self):
        A.__init__(self)
        print "C"

class D(B, C):
    def __init__(self):
        B.__init__(self)
        C.__init__(self)
        print "D"

D()
code:
A
B
A
C
D
Not that you should use multiple inheritance like this anyway.

Cingulate
Oct 23, 2012

by Fluffdaddy
My main python installation is Python3 from anaconda, and python calls the anaconda Py3k. I want to install a package that is Python 2.x only, and asks for python to call a Python 2.x. What's the best way for going about this?

Also, it seems readthedocs.org is down right now?

Edit: I'm on a Mac, if this matters.

Cingulate fucked around with this message at 15:31 on Dec 22, 2014

Nippashish
Nov 2, 2005

Let me see you dance!

Cingulate posted:

My main python installation is Python3 from anaconda, and python calls the anaconda Py3k. I want to install a package that is Python 2.x only, and asks for python to call a Python 2.x. What's the best way for going about this?

Create a conda environment with python 2 and install it in there.

Thermopyle
Jul 1, 2003

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

Aaronicon posted:

Speaking of that terrible libtcodpy tutorial, is there any practical difference between going

Python code:
ClassName(BaseClass):

    def __init__(self):
        super(ClassName, self).__init__()
vs

Python code:
ClassName(BaseClass):

    def __init__(self):
        BaseClass.__init__(self)
I believe they both accomplish the same thing but the latter seems a lot cleaner and 'pythonic' to me. The super() syntax doesn't feel nice to me, for lack of any other actual reason. I mean arguably the second method means that you have to change the name of the function should you ever change the name of the BaseClass, but we live in the year 2014 and if you don't have an IDE with find/replace I don't know what to tell you.

Super really comes into its own when you're dealing with multiple inheritance and when you have a larger chain of ancestors. Of course, that sort of scenario is over-used and complicated.

However, Python 3's super is much nicer looking than Python 2's. You just call super().__init__(). Of course, by being nicer looking it requires a bit of magic compiler intervention.

As I'm mostly just using Python 3 I just user super rather than directly calling the baseclass because it's not as dumb looking as Python 2's.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

Hammerite posted:

I'm coming back to a personal project that I set aside a while ago. The project involves using PLY to create a parser for a domain specific language. There is a long and detailed help file, which is great, but one thing that strikes me as weird is this:


This business of treating functions based on the order they were defined - is that something that is used by other Python projects? Is it something that is guaranteed to not be broken by future versions of Python? It seems like a funny thing to rely on.

The way you create a lexer (by calling a function in the module rather than by calling Lexer()) is awkward too, as I want to subclass the Lexer class to tweak its behaviour but it's set up in such a way that it's hard to know how to do that. Just having a wrapper class that contains a Lexer is not a perfect solution, as the token parameters to so-called "rule" functions/methods contain a reference to the Lexer object.

In regards to the problem of subclassing the Lexer class, it seems like an approach like the following should work, although it's annoying to have to dick around rather than just be able to subclass it...

Python code:
import ply.lex.Lexer as BaseLexer

class CustomisedLexer (BaseLexer):
    def __init__ (self):
        raise Exception("Use from_lexer() to create a CustomisedLexer from a PLY Lexer.")

    @classmethod
    def from_lexer (cls, base_lexer):
        base_lexer.__class__ = cls
        # other initialisation of extension data...
        return base_lexer

    # other changes to the lexer behaviour...

Adbot
ADBOT LOVES YOU

BigRedDot
Mar 6, 2008

Cingulate posted:

My main python installation is Python3 from anaconda, and python calls the anaconda Py3k. I want to install a package that is Python 2.x only, and asks for python to call a Python 2.x. What's the best way for going about this?

Also, it seems readthedocs.org is down right now?

Edit: I'm on a Mac, if this matters.

code:
conda create -n py27 python=2.7 anaconda   # could also leave off anaconda and just list the conda pkgs you want explicitly
then
code:
source activate py27
Then install your package however, conda, pip, by hand. It will go in the y27 environment.

  • Locked thread