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
SurgicalOntologist
Jun 17, 2004

KICK BAMA KICK posted:

Here's the problem. map is the name of a built-in function. Either a) the code you're c/ping must have elsewhere redefined map to refer to a list of lists or something to that effect, whose items you could access with the [x][y] syntax or b) you made a typo -- hopefully this, because the former would mean you're reading some dumb code. __getitem__ is the method that is silently invoked when you access an element of a list by index, or an element of a dictionary by key, etc. Because map is just a function, and functions don't have elements you can access with that syntax, it doesn't have a __getitem__ method and thus Python complains.

So either you mistyped map in place of something else (like fov_map perhaps?) or you need to incorporate the code that defines map. In the unlikely event that this code does redefine a very basic and useful built-in function rather than simply coming up with a unique name, consider learning from another source because that's a huge red flag.

Well you're getting the error because map is a builtin function and therefore you can't index into it like map[x]. Indexing uses the __getitem__ method under the hood; saying map doesn't have __getitem__ is the same as saying you can't index into it.

Without looking at the rest of the code or libtcod, my guess is you want to replace the two appearances of map with fov_map. Unless you have another sort of map as well.

E: Holy crap, beaten badly.

SurgicalOntologist fucked around with this message at 05:11 on Aug 14, 2014

Adbot
ADBOT LOVES YOU

Space Kablooey
May 6, 2009


KICK BAMA KICK posted:

So either you mistyped map in place of something else (like fov_map perhaps?) or you need to incorporate the code that defines map. In the unlikely event that this code does redefine a very basic and useful built-in function rather than simply coming up with a unique name, consider learning from another source because that's a huge red flag.

Also this again, for effect.

SurgicalOntologist
Jun 17, 2004

Confirmed: it's not a typo. The tutorial code is kind of scary.

Python code:
global map
To actually give useful advice: make a class or two, every function that need one or more globals should be a method on one of these classes and every global an attribute. Use the distribution of globals among the function to help decide if there are any natural groupings for making more than one class, if not just make one.

SurgicalOntologist fucked around with this message at 05:16 on Aug 14, 2014

girl dick energy
Sep 30, 2009

You think you have the wherewithal to figure out my puzzle vagina?
Alright, I'll go ahead and change everything, and take the tutorial with a grain of salt from here on. Will report back soon with results, or exciting new errors in learning code from people who overwrite global functions.

SurgicalOntologist posted:

To actually give useful advice: make a class or two, every function that need one or more globals should be a method on one of these classes and every global an attribute. Use the distribution of globals among the function to help decide if there are any natural groupings for making more than one class, if not just make one.
I'm going to be frank with you.

I understood precisely none of that.

Edit Well, okay, that's not strictly true. I know how to make a class. I just don't know how that applies in the context of this. Let's see what I can MacGyver together, though.

Edit2 I'm starting to feel like I might just have more luck starting again from scratch. It's only 350 lines, and better figuring out what and how to make this work properly now than having a horrible messy kludge of code that's 6000 lines long and is completely unmanageable.

girl dick energy fucked around with this message at 05:32 on Aug 14, 2014

KICK BAMA KICK
Mar 2, 2009

Poison Mushroom posted:

I'm going to be frank with you.

I understood precisely none of that.

Edit Well, okay, that's not strictly true. I know how to make a class. I just don't know how that applies in the context of this. Let's see what I can MacGyver together, though.
Bad:
Python code:
x = 5

def set_x_to_7():
    global x
    x = 7

def set_x_to_10():
    global x
    x = 10
Better:
Python code:
class XHolder:
    def __init__(self):
        self.x = 5

    def set_x_to_7(self):
        self.x = 7

    def set_x_to_10(self):
        self.x = 10

my_object = XHolder()
my_object.set_x_to_7()
That's super-simplified and would be weird if it was all you were doing but maybe it illustrates the general concept.

quote:

Edit2 I'm starting to feel like I might just have more luck starting again from scratch. It's only 350 lines, and better figuring out what and how to make this work properly now than having a horrible messy kludge of code that's 6000 lines long and is completely unmanageable.
Separating functionality into classes will really help with this; you might want to go a step further and look up the basics of using modules -- separate files of code that you import, just like the libraries you've been using.

SurgicalOntologist
Jun 17, 2004

Yeah I hadn't thought about it any deeper than that.

Basically, Poison Mushroom, a common problem is wanting to have access to some repertoire of variables from many functions. There are various ways to achieve this:

- Make these variables globals. This is the worst solution. It's easy at first, but leads to strange errors and hard-to-debug code.

- Pass these variables around as parameters and/or return them. This is probably the most common solution. But as you get more and more of these variables it gets tedious.

- Make a class, put the variables on the class as attributes, and pass the instance around. Remember how when you write methods on a class, you always make the first one self? Methods are sort of just passing around an instance. If you make these functions methods, you don't need to explicitly pass the instance, it will be self.

In your example you could make a class like GameState or something, and methods could access self.map or self.player instead of globals.

girl dick energy
Sep 30, 2009

You think you have the wherewithal to figure out my puzzle vagina?

SurgicalOntologist posted:

Yeah I hadn't thought about it any deeper than that.

Basically, Poison Mushroom, a common problem is wanting to have access to some repertoire of variables from many functions. There are various ways to achieve this:

- Make these variables globals. This is the worst solution. It's easy at first, but leads to strange errors and hard-to-debug code.

- Pass these variables around as parameters and/or return them. This is probably the most common solution. But as you get more and more of these variables it gets tedious.

- Make a class, put the variables on the class as attributes, and pass the instance around. Remember how when you write methods on a class, you always make the first one self? Methods are sort of just passing around an instance. If you make these functions methods, you don't need to explicitly pass the instance, it will be self.

In your example you could make a class like GameState or something, and methods could access self.map or self.player instead of globals.

KICK BAMA KICK posted:

Separating functionality into classes will really help with this; you might want to go a step further and look up the basics of using modules -- separate files of code that you import, just like the libraries you've been using.

I've decided to take a compromise between this and the old stuff. Thanks to Notepad++ being loving magic, I was able to CTRL+Z all the back to before I put in the first FOV bits. I'm going to take everything that's left, salvage all that I can into modules or just better code, and then go through the rest of the tutorial as a kind of rough guide, rather than just copying him. It'll be a rougher road with more bumps and bugs and probably all kinds of stupid mistakes, but it's better than either trying to figure all this poo poo out myself, OR just starting from scratch and fixing what it breaks as I go.

Edit Really stupid question, how would I get Python to search for modules inside a sub-directory, like a folder to keep them all in? I know it has something to do with sys.path and PYTHONPATH, but I'll be damned if I can figure out what.

Edit2 Would it be site.addsitedir(sitedir, known_paths=None)? And if so, would the sitedir be 'c:\whatever\whatever\destination' folder, or would it just be searching straight from the directory that the file's running from? (And thus, just '\destinationfolder'?) I'm going to gently caress around with this and hope I don't break something important.

girl dick energy fucked around with this message at 07:13 on Aug 14, 2014

fletcher
Jun 27, 2003

ken park is my favorite movie

Cybernetic Crumb

Poison Mushroom posted:

Thanks to Notepad++ being loving magic, I was able to CTRL+Z all the back to before I put in the first FOV bits.

Now is a great time to learn the basics of git. There's only a few commands you'll need to use at first and it is amazing what it is capable of. I would stick with the command line interface for now (msysgit), no need for a GUI.

https://github.com/blog/120-new-to-git

QuarkJets
Sep 8, 2008

Poison Mushroom posted:

I've decided to take a compromise between this and the old stuff. Thanks to Notepad++ being loving magic, I was able to CTRL+Z all the back to before I put in the first FOV bits. I'm going to take everything that's left, salvage all that I can into modules or just better code, and then go through the rest of the tutorial as a kind of rough guide, rather than just copying him. It'll be a rougher road with more bumps and bugs and probably all kinds of stupid mistakes, but it's better than either trying to figure all this poo poo out myself, OR just starting from scratch and fixing what it breaks as I go.

Edit Really stupid question, how would I get Python to search for modules inside a sub-directory, like a folder to keep them all in? I know it has something to do with sys.path and PYTHONPATH, but I'll be damned if I can figure out what.

Edit2 Would it be site.addsitedir(sitedir, known_paths=None)? And if so, would the sitedir be 'c:\whatever\whatever\destination' folder, or would it just be searching straight from the directory that the file's running from? (And thus, just '\destinationfolder'?) I'm going to gently caress around with this and hope I don't break something important.

This seems like a reasonable path to take. Feel free to ask any questions in here

There are several ways to be able to find modules inside of a sub-directory:

1) Modify your PYTHONPATH environmental variable. In Windows, writing instructions for this is a bit of a pain in the rear end because the names of things change slightly depending on what version you're on, but on Windows 8 you'd right click on This PC (or My Computer), select Properties, select Advanced System Settings, select Environmental Variables. At the top should be a list of your user variables. If PYTHONPATH is defined there, then edit it by adding a semicolon to the end of whatever's there and then typing in (or copy-pasting) the path of whatever sub-directory that you want to use for your python projects. If it's not defined, add a new variable called PYTHONPATH and copy-paste the sub-directory path as the value (you don't need a semicolon anywhere in this case). You should try to do this one, if you can, because if you gently caress something up then nothing breaks, you just won't be able to import your homemade modules until you fix the issue. It sounds difficult, but it's actually pretty easy, and once it's set up you never have to do it again.

2) Use regedit to modify the \SOFTWARE\Python\PythonCore\version\PythonPath in HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE. Like with the environmental variable, entries need to be separated by semicolons. If you look at the PythonPath in HKEY_LOCAL_MACHINE, you'll likely find all of the base Python directories. You can gently caress up your Python installation by messing around in regedit and making the wrong change, so I wouldn't suggest doing this.

3) Create your project in a directory that is already included in your sys.path, such as directories that contain core Python modules (do not actually do this, as it will make your project hard to manage)

4) This is sloppier, but you can just modify the sys.path in whatever script that you're using to launch your game.
Python code:
import sys
sys.path.append('C:\whatever\my_games\python\butts\')

from butt_module import furry_torture_simulator
This is generally fine, especially if you're just screwing around or trying something out. However, this means that your submodules will also need that line, or else they won't be able to see each other.

5) You could also use site, but site is just going to extend sys.path anyway. It also does some other stuff that you don't need and is a bit of a coding horror

QuarkJets fucked around with this message at 09:57 on Aug 14, 2014

ShadowHawk
Jun 25, 2000

CERTIFIED PRE OWNED TESLA OWNER

fletcher posted:

Now is a great time to learn the basics of git. There's only a few commands you'll need to use at first and it is amazing what it is capable of. I would stick with the command line interface for now (msysgit), no need for a GUI.

https://github.com/blog/120-new-to-git
It's way easier to learn details of git with one of the better guis (eg sourcetree) imo.

That said if you're replacing "undo" you might as well just be committing the entire file at once every time you run it and get a compilable result.

Space Kablooey
May 6, 2009


QuarkJets posted:

This seems like a reasonable path to take. Feel free to ask any questions in here

There are several ways to be able to find modules inside of a sub-directory:
<snip>

What you posted isn't what virtualenv sets out to do?

girl dick energy
Sep 30, 2009

You think you have the wherewithal to figure out my puzzle vagina?
I have another dumb question about the conversion from globals to classes.

Here's a sample of the old, awful code.
code:
def make_map():
	global map
	
	#Filling the map with unblocked tiles.
	map = [[ Tile(True)
		for y in range(MAP_HEIGHT) ]
			for x in range(MAP_WIDTH) ]

#Making that rectangle into a room.
def create_room(room):
	global map
	#Go through the tiles in the rectangle and make them passable.
	for x in range(room.x1 + 1, room.x2):
		for y in range(room.y1 + 1, room.y2):
			map[x][y].blocked = False
			map[x][y].block_sight = False
If I was to convert that to a class, would that be...

code:
class gamemap:
	#Filling the map with unblocked tiles.
	gamemap = [[ Tile(True)
		for y in range(MAP_HEIGHT) ]
			for x in range(MAP_WIDTH) ]

def create_room(room):
	#Go through the tiles in the rectangle and make them passable.
	for x in range(room.x1 + 1, room.x2):
		for y in range(room.y1 + 1, room.y2):
			gamemap[x][y].blocked = False
			gamemap[x][y].block_sight = False
As a small sample, or am I missing something else major?

girl dick energy fucked around with this message at 18:16 on Aug 14, 2014

SurgicalOntologist
Jun 17, 2004

Yeah, some major problems there, you might want to read up on classes, look at some examples. Here's a basic skeleton to get you started:

Python code:
class GameState:
    def __init__(self, player, width=MAP_WIDTH, height=MAP_HEIGHT):
        self.player = player
        # Fill the map with unblocked tiles.
        self.map = ...

    def create_room(self, room):
        # Go through the tiles in the rectangle and make them passable.
        # refer to self.map in this method
        ...
Basically, by putting the map creation in __init__ as self.map you make it an instance attribute instead of a class atrribute. A class attribute is always the same for every GameState whereas an instance attribute reflects one specific GameState. Instance attributes are more common and you should stick with them for now. The idea is that every method has self as its first parameter, which is some specific GameState instance. You can pass around variables which refect the current state as attributes of self, e.g. self.map.

This way, values that you need in a function can come from two places: explicitly passed to the function, like room in create_room, or attributes of the current game state, this is how other methods will have access to self.player and self.map. But note that this second way of getting values is just an indirection on the first way--you're still passing the values to the function, via the self parameter.

I added self.player as an example of another attribute. The way I have it set up you would create the player first and then pass it to the GameState. Alternatively you could create the player from scratch within __init__.

Also note that having the map be self.map (from inside a method) or state.map (from elsewhere, where state is a GameState instance) means that the previous problem of conflicting with the builtin function is solved. No need to call it gamemap, IMO, as GameState.gamemap is redundant.

SurgicalOntologist fucked around with this message at 18:32 on Aug 14, 2014

girl dick energy
Sep 30, 2009

You think you have the wherewithal to figure out my puzzle vagina?
Okay. I probably ended up trying to run before I could crawl, but I'll do what I can. Let me see if I'm groking the concept.

A class is a sort of blueprint for making an object or a function, something you'll need to do a lot. Classes are to functions as constants are to magic numbers. If I wanted to create a lot of gamemaps, then it would behoove me to make a Class for them, something to repeat the map-making code over and over. Something like Floor or Level.

So I'd put my map-generation code into that class under def __init__, and every time something from the code calls to create something from the Floor class, it'd run all the mapmaking code right then, with room to also include in the class possible variations on the formula? (Larger rooms, fewer rooms, a different tunnel generation process, etc?)

Space Kablooey
May 6, 2009


Poison Mushroom posted:

A class is a sort of blueprint for making an object or a function, something you'll need to do a lot. Classes are to functions as constants are to magic numbers. If I wanted to create a lot of gamemaps, then it would behoove me to make a Class for them, something to repeat the map-making code over and over. Something like Floor or Level.

So I'd put my map-generation code into that class under def __init__, and every time something from the code calls to create something from the Floor class, it'd run all the mapmaking code right then, with room to also include in the class possible variations on the formula? (Larger rooms, fewer rooms, a different tunnel generation process, etc?)

In a nutshell, yes, that is pretty much it.

SurgicalOntologist
Jun 17, 2004

Poison Mushroom posted:

A class is a sort of blueprint for making an object or a function, something you'll need to do a lot.

Yes and no. Technically correct, I think, but the best way of thinking of classes is as a neatly contained bundle of state and behavior that acts on said state (well, the class is a blueprint for creating that bundle, the bundle is the instance). As opposed to a variable which is only state or a function which is only behavior. It can still be useful to make a class for something like game state that you only plan to instantiate once, because it provides a nice package for giving all the methods (the behavior) access to the attributes (the state).

The "do I need a class here" checklist has two items: state and behavior. As is, you're representing the map as a list of lists, which I think is fine. I don't think you should make a map class until you have some behavior that makes more sense to package with the map than with the GameState. Doesn't mean you shouldn't make a create_blank_map function though, if it's something you do more than once.

SurgicalOntologist fucked around with this message at 19:55 on Aug 14, 2014

QuarkJets
Sep 8, 2008

HardDisk posted:

What you posted isn't what virtualenv sets out to do?

It is, but I've never messed with that on Windows

QuarkJets
Sep 8, 2008

Poison Mushroom posted:

Okay. I probably ended up trying to run before I could crawl, but I'll do what I can. Let me see if I'm groking the concept.

A class is a sort of blueprint for making an object or a function, something you'll need to do a lot. Classes are to functions as constants are to magic numbers. If I wanted to create a lot of gamemaps, then it would behoove me to make a Class for them, something to repeat the map-making code over and over. Something like Floor or Level.

So I'd put my map-generation code into that class under def __init__, and every time something from the code calls to create something from the Floor class, it'd run all the mapmaking code right then, with room to also include in the class possible variations on the formula? (Larger rooms, fewer rooms, a different tunnel generation process, etc?)

As an example, let's say that you want to be able to create the map more than once, but you definitely want to create a map when the game begins. Here's one way that you could do that

Python code:
#Define maximum map dimensions
MAX_MAP_WIDTH = 10
MAX_MAP_HEIGHT = 10
#A nice option is to put these two variables into a separate file and import them
#For example, you could define them in game_constants.py and then in this script
#you could have "from game_constants import MAX_MAP_WIDTH, MAX_MAP_HEIGHT"
#This is useful if you have constants that are used in more than one module

class GameState:
    def __init__(self):
        self.map = self.create_map()
        #And maybe you do some other things when the game gets created.
        #Maybe you populate a menu:
        self.menu = self.create_menu()
        #etc


    def create_map(self, X=MAX_MAP_WIDTH, Y=MAX_MAP_HEIGHT):
        #This method creates a new map anytime that it gets called
        #The last two parameters are options with defaults.  
        #This means that I can not provide X and Y, and they'll 
        #use whatever values MAX_MAP_WIDTH and MAX_MAP_HEIGHT 
        #are set to.
        #Maybe I don't want a map to ever exceed some maximum 
        #dimensions, which is why I named the variables MAX_etc.
        #Let's check to make sure:
        if X > MAX_MAP_WIDTH:
            X = MAX_MAP_WIDTH
        if Y > MAX_MAP_HEIGHT:
            Y = MAX_MAP_HEIGHT

        #Now create the map
        self.map = map = [[ Tile(True)
		for iy in range(Y) ]
			for ix in range(X) ]

    def create_half_map(self):
        #This method creates a map with dimensions that are
        #half of the maximum size.  It just calls create_map
        #with some specific inputs
        self.create_map(MAX_MAP_WIDTH/2, MAX_MAP_HEIGHT/2)

    def return_center_of_map(self):
        #This method returns the center of the map
        Nx = len(self.map)
        Ny = len(self.map[Nx/2])
        return self.map[Nx/2][Ny/2]

#Okay let's say that we want to create a game
new_game = GameState()

#The line above resulted in everything in __init__ 
#getting called, so the game state has a map
print len(new_game.map)

#Let's make the map half of its normal size
new_game.create_half_map()
print len(new_game.map) #This will print something new

#We can call methods that we defined for the class.
#I want to create a new 4x7 map:
new_game.create_map(4,7)
print len(new_game.map) #the map changed again!

#Okay one more, define a map that is MAX_MAP_WIDTH by 4
#We do this by specifying which parameter we want to change.  
#We've left X at the default value of MAX_MAP_WIDTH
new_game.create_map(y=4)
print len(new_game.map)
print new_game.map[1][3] 

fletcher
Jun 27, 2003

ken park is my favorite movie

Cybernetic Crumb
How do I handle user credentials that are required for running integration tests? I was thinking environment variables might be the way to go. Right now I just have them hard coded in my setUp() method but I'm thinking I probably shouldn't commit that to source control.

thegasman2000
Feb 12, 2005
Update my TFLC log? BOLLOCKS!
/
:backtowork:
So I am working my way through the "learn python the hard way" course and its great. I think I have hit an issue with my dev enviroment, as I am using Pycharm and not the command line as per the instructions.

In exercise 13 it asks us to do this...

code:
from sys import argv

script, first, second, third = argv

print "The script is called:", script
print "Your first variable is:", first
print "Your second variable is:", second
print "Your third variable is:", third
Firstly I don't understand what argv is and secondly its giving me errors in Pycharm. Is this important? I understand its importing argv from the sys module. Can i access that from pycharm?

Crosscontaminant
Jan 18, 2007

argv is a sequence of the commandline string used to launch the program, split on spaces.

Python code:
#!/usr/bin/env python
import sys

print(" ".join(sys.argv))

quote:

[thomas@chansey ~]♣ ./test.py one two three
./test.py one two three

I don't know anything about Pycharm, but it's probably failing because the way their code is written it will only work with exactly three arguments passed to it. You'll need to give us the exception it's throwing.

onionradish
Jul 6, 2006

That's spicy.

thegasman2000 posted:

Can i access that from pycharm?
Under PyCharm's 'Run' menu, choose 'Edit Configurations...' and enter the arguments in the 'Script Parameters' field. For Crosscontaminant's example, you'd enter 'one two three' (without the quotes). The next time you run the script it will use those parameters.

JHVH-1
Jun 28, 2002

fletcher posted:

How do I handle user credentials that are required for running integration tests? I was thinking environment variables might be the way to go. Right now I just have them hard coded in my setUp() method but I'm thinking I probably shouldn't commit that to source control.

I started making scripts that go across prod and pre-prod with the same code using configparser https://wiki.python.org/moin/ConfigParserExamples

For more complicated stuff I created an sqlite database.

KernelSlanders
May 27, 2013

Rogue operating systems on occasion spread lies and rumors about me.
You can also open a terminal, navigate to the PyCharm project directory, and run the script from the command line there.

Thermopyle
Jul 1, 2003

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

KernelSlanders posted:

You can also open a terminal, navigate to the PyCharm project directory, and run the script from the command line there.

Or go to Tools > Open Terminal...

KernelSlanders
May 27, 2013

Rogue operating systems on occasion spread lies and rumors about me.
Is there a good way to filter on a list of tuples? For example, let's say I want to sum the second values where something about the first value is true. This can be done with a list comprehension, but feels a little clunky.

Python code:
my_array = [('a', 1), ('b', 2), ('c', 3), ('a', 4)]
sum([x[1] for x in my_array if x[0] == 'a'])
#> 5

' '.join([x[0] for x in my_array if mod(x[1],2) == 0])
#> 'b a'
Obviously that works, but something about it doesn't seem quite right. I suppose I could write some filter/transform/acumulate function, but it really seems like there should be a better builtin.

Python code:
def fta(filter_func, transform_func, accumulate_func, input_list):
    return accumulate_func(map(transform_func, filter(filter_func, input_list)))


fta(lambda x: x[0]=='a', lambda x: x[1], lambda x: sum(x), my_array)
#> 5
Actually, now that I wrote it down, that looks much worse.

ShadowHawk
Jun 25, 2000

CERTIFIED PRE OWNED TESLA OWNER

KernelSlanders posted:

Is there a good way to filter on a list of tuples? For example, let's say I want to sum the second values where something about the first value is true. This can be done with a list comprehension, but feels a little clunky.

Python code:
my_array = [('a', 1), ('b', 2), ('c', 3), ('a', 4)]
sum([x[1] for x in my_array if x[0] == 'a'])
#> 5

' '.join([x[0] for x in my_array if mod(x[1],2) == 0])
#> 'b a'
Obviously that works, but something about it doesn't seem quite right. I suppose I could write some filter/transform/acumulate function, but it really seems like there should be a better builtin.

Python code:
def fta(filter_func, transform_func, accumulate_func, input_list):
    return accumulate_func(map(transform_func, filter(filter_func, input_list)))


fta(lambda x: x[0]=='a', lambda x: x[1], lambda x: sum(x), my_array)
#> 5
Actually, now that I wrote it down, that looks much worse.
No need to construct a list, just use a generator expression:

Python code:
my_array = [('a', 1), ('b', 2), ('c', 3), ('a', 4)]
sum(x[1] for x in my_array if x[0] == 'a')
#> 5

' '.join(x[0] for x in my_array if x[1]%2 == 0)
#> 'b a'
I'm not sure how it could look any smoother, and it does everything correctly (eg only holding the sum and one object of the filtered list in memory at a time)


In general, just think of python's builtins that tend to operate on lists (or stuff that can be iterated) as generally working on generators as well, and that you often actually want to use the generator versions. You were right to be suspicious of constructing an entirely separate list only to immediately traverse it once and then throw it away.

ShadowHawk fucked around with this message at 18:40 on Aug 17, 2014

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord
Your example is kind of odd, why can't you use a dictionary? Or even something like this:

Python code:
my_list = ['a', 'b', 'c', 'a']
sum(i+1 for i, c in enumerate(my_list) if c == 'a')
# 5

' '.join(c for i, c in enumerate(my_list) if (i+1)%2 == 0)
# 'b a'

QuarkJets
Sep 8, 2008

KernelSlanders posted:

Is there a good way to filter on a list of tuples? For example, let's say I want to sum the second values where something about the first value is true. This can be done with a list comprehension, but feels a little clunky.

Python code:
my_array = [('a', 1), ('b', 2), ('c', 3), ('a', 4)]
sum([x[1] for x in my_array if x[0] == 'a'])
#> 5

' '.join([x[0] for x in my_array if mod(x[1],2) == 0])
#> 'b a'
Obviously that works, but something about it doesn't seem quite right. I suppose I could write some filter/transform/acumulate function, but it really seems like there should be a better builtin.

Python code:
def fta(filter_func, transform_func, accumulate_func, input_list):
    return accumulate_func(map(transform_func, filter(filter_func, input_list)))


fta(lambda x: x[0]=='a', lambda x: x[1], lambda x: sum(x), my_array)
#> 5
Actually, now that I wrote it down, that looks much worse.

Yeah, that final solution is sort of :psyduck:

I think that your first solution looks fine. It looks clunky because the input is clunky.

KernelSlanders
May 27, 2013

Rogue operating systems on occasion spread lies and rumors about me.

Symbolic Butt posted:

Your example is kind of odd, why can't you use a dictionary? Or even something like this:

Python code:
my_list = ['a', 'b', 'c', 'a']
sum(i+1 for i, c in enumerate(my_list) if c == 'a')
# 5

' '.join(c for i, c in enumerate(my_list) if (i+1)%2 == 0)
# 'b a'

Because my_list is the output of a library function that returns a list of tuples. I have no idea why it does this rather than returning a dictionary. Also, the fact that the second values of my tuples were 1,2,3,4 was just a poor choice in setting up my example and could be anything. I do think your tuple expansion combined with ShadowHawk's point about using the generator leads to something pretty clean.

Python code:
my_list = [('a', 1), ('b', 2), ('c', 3), ('a', 4)]
sum(num for string, num in my_list if string == 'a')
#> 5
I think the two problems with the original were the allocating of a list to be immediately tossed and the cryptic x[0], x[1] calls. This seems to fix both.

KernelSlanders fucked around with this message at 20:17 on Aug 17, 2014

Nippashish
Nov 2, 2005

Let me see you dance!
e: nm I'm dumb and didn't read the question

QuarkJets
Sep 8, 2008

KernelSlanders posted:

Because my_list is the output of a library function that returns a list of tuples. I have no idea why it does this rather than returning a dictionary. Also, the fact that the second values of my tuples were 1,2,3,4 was just a poor choice in setting up my example and could be anything. I do think your tuple expansion combined with ShadowHawk's point about using the generator leads to something pretty clean.

Python code:
my_list = [('a', 1), ('b', 2), ('c', 3), ('a', 4)]
sum(num for string, num in my_list if string == 'a')
#> 5
I think the two problems with the original were the allocating of a list to be immediately tossed and the cryptic x[0], x[1] calls. This seems to fix both.

From your output example, it looks like the keys are non-unique, so a dictionary isn't really suitable. But yeah, this solution looks pretty great if you're having to deal with tuples in that form

Symbolic Butt
Mar 22, 2009

(_!_)
Buglord
Unpacking is great for improving readability. Unpack everything :getin:

QuarkJets posted:

From your output example, it looks like the keys are non-unique, so a dictionary isn't really suitable. But yeah, this solution looks pretty great if you're having to deal with tuples in that form

The keys could be the numbers instead of the characters, that's why I thought about just using a list of characters.

ShadowHawk
Jun 25, 2000

CERTIFIED PRE OWNED TESLA OWNER

Symbolic Butt posted:

Unpacking is great for improving readability. Unpack everything :getin:
Wisdom.

KernelSlanders posted:

Python code:
my_list = [('a', 1), ('b', 2), ('c', 3), ('a', 4)]
sum(num for string, num in my_list if string == 'a')
#> 5
I think the two problems with the original were the allocating of a list to be immediately tossed and the cryptic x[0], x[1] calls. This seems to fix both.
This is indeed even better.

One other possibility, if these tuples are appearing elsewhere in your code, is a named tuple. You can't easily declare them inline during a list creation, but if the API you're using is returning tuples you could namify them as you get them (eg to build your initial list), or perhaps replace the list in place.

Python code:
from collections import namedtuple
Pair = namedtuple('pair', ['string', 'num'])

named_list = [Pair._make(x) for x in my_list]
sum(x.num for x in named_list if x.string == 'a') # pretty, but requires a premade list

sum(y.num for y in (Pair._make(x) for x in my_list) if y.string == 'a') # Ugly way to do it inline

QuarkJets
Sep 8, 2008

Symbolic Butt posted:

Unpacking is great for improving readability. Unpack everything :getin:


The keys could be the numbers instead of the characters, that's why I thought about just using a list of characters.

Are the numbers necessarily unique, though? I'd assume not

Harriet Carker
Jun 2, 2009

Are there any highly recommended books for learning Python? I know the basics and am ready to move to intermediate/advanced topics. A book with problems/exercises followed by solutions and discussion could be great. I've never learned coding from a book before so I'm not sure what to look for.

Blinkz0rz
May 27, 2001

MY CONTEMPT FOR MY OWN EMPLOYEES IS ONLY MATCHED BY MY LOVE FOR TOM BRADY'S SWEATY MAGA BALLS
Is it terrible practice to use ast.literal_eval()?

Right now I'm faux serializing lists by saving the list itself into a CharField (don't ask, this project is riddled with issues like this.) I'm trying to decide whether it makes sense to serialize to an actual serialization format and then deserialize instead of using literal_eval() or if I can get away with it. Thoughts?

seance snacks
Mar 30, 2007

So I finally took the leap today and picked up python. I really like it so far and its gone better than any previous attempts I'd made at learning a language. I spent today making a simple button based GUI to launch various scripts.

Anyway, my problem so far is that I keep getting errors because all the commands I look up for 2.x. Are there any good sites for 3.x stuff?

seance snacks fucked around with this message at 03:49 on Aug 21, 2014

Thermopyle
Jul 1, 2003

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

Noslo posted:

So I finally took the leap today and picked up python. I really like it so far and its gone better than any previous attempts I'd made at learning a language. I spent today making a simple button based GUI to launch various scripts.

Anyway, my problem so far is that I keep getting errors because all the commands I look up for 2.x. Are there any good sites for 3.x stuff?

There's hardly any difference between 2 and 3 that you will likely encounter.

Keep plugging away, and in a few days you'll probably learn all the most frequently encountered differences.

Adbot
ADBOT LOVES YOU

Literally Elvis
Oct 21, 2013

Noslo posted:

So I finally took the leap today and picked up python. I really like it so far and its gone better than any previous attempts I'd made at learning a language. I spent today making a simple button based GUI to launch various scripts.

Anyway, my problem so far is that I keep getting errors because all the commands I look up for 2.x. Are there any good sites for 3.x stuff?

http://www.diveintopython3.net

  • Locked thread