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.
 
  • Post
  • Reply
Ghost of Reagan Past
Oct 7, 2003

rock and roll fun

Boris Galerkin posted:

Well I just had a frustrating time figuring out what was wrong with a part of my code when it turns out it was numpy being weird.

So I have a numpy array where some values are inf and some values are nan. I create a Boolean list of where these values in the array are inf/nan, and then I use these indices to do something to another array.

Like so:

code:
import numpy as np

a = np.array([1, np.sqrt(-1), np.nan, np.inf])  # [1, nan, nan, inf]

print(a == np.inf)
# F, F, F, T, as expected

print(a == np.nan)
# F, F, F, F, which is wrong

print(np.isnan(a))
# F, T, T, F
Is there a reason it does this? Does np.nan has an actual numerical value or something? I would have thought it would be treated in the same way as None where it just "is" or "isn't."


code:
>>> np.nan == np.nan
False
NaN is equal to nothing, not even itself.

Adbot
ADBOT LOVES YOU

Eela6
May 25, 2007
Shredded Hen
NaN == n is False, even if n is NaN. It's in the IEEE specificiations for floating point numbers. This is occasionally inconvenient but it's the way it is - the spec is older than Python!

This is true both for numpy and Python's built-in float type, though you're unlikely to encounter NaN in that case, since most operations that produce it will raise an exception first.

Eela6 fucked around with this message at 16:14 on Jul 4, 2017

Thermopyle
Jul 1, 2003

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

People complain about the same thing in javascript all the time. It's just the standards-defined behavior we're stuck with.

As for the why, I think it boils down to the limitation of the hardware and software available at the time the standard was created. See this SO answer and the related comments.

Dominoes
Sep 20, 2007

Additionally, the builtin math.isnan and np.isnan work on several nan-like-types.

Boris Galerkin
Dec 17, 2011

I don't understand why I can't harass people online. Seriously, somebody please explain why I shouldn't be allowed to stalk others on social media!
Ok cool thanks for the info. I figured it was a spec related thing but I guess this is the first time I've ever used a thing where nan or dividing by zero doesn't crash your program.

Eela6 posted:

NaN == n is False, even if n is NaN. It's in the IEEE specificiations for floating point numbers. This is occasionally inconvenient but it's the way it is - the spec is older than Python!

This is true both for numpy and Python's built-in float type, though you're unlikely to encounter NaN in that case, since most operations that produce it will raise an exception first.

Yep I explicitly used numpy arrays here cause I figured it was easier to just handle the nan/inf values of they ever arose rather than pre-checking.

Malcolm XML
Aug 8, 2009

I always knew it would end like this.

Boris Galerkin posted:

Ok cool thanks for the info. I figured it was a spec related thing but I guess this is the first time I've ever used a thing where nan or dividing by zero doesn't crash your program.


Yep I explicitly used numpy arrays here cause I figured it was easier to just handle the nan/inf values of they ever arose rather than pre-checking.

Behold the quiet nan

Boris Galerkin
Dec 17, 2011

I don't understand why I can't harass people online. Seriously, somebody please explain why I shouldn't be allowed to stalk others on social media!

Malcolm XML posted:

Behold the quiet nan

:hmm_emoji:

That sounds like a terrible thing now that I think about it.

Mirthless
Mar 27, 2011

by the sex ghost
Hey guys, I am trying to learn how to program and I'm making some progress but I am constantly worried I am doing outrageously embarrassing poo poo with my code and I find I'm second guessing it a lot

There's a lot of tutorials out there on how to do stuff in Python but is there a big list anywhere of things not to do? Like, "This works, but never do it"? I know about PEP 8 but I'm thinking less "follow this style" and more "what the gently caress are you doing you idiot"

My current project is a character generator for AD&D - right now, I'm storing the character's information in a big dictionary, with nested dictionaries:

code:
Player = {                
    'Name' : "Blank",     
    'Race' : "Blank",     
    'Stats' : { 
        'STR': {'Base' : 0,'Bonus' : 0,}, 
        'CON': {'Base' : 0,'Bonus' : 0,}, 
        'DEX': {'Base' : 0,'Bonus' : 0,}, 
        'INT': {'Base' : 0,'Bonus' : 0,}, 
        'WIS': {'Base' : 0,'Bonus' : 0,}, 
        'CHA': {'Base' : 0,'Bonus' : 0,}, 
            },
    'Class' : "Blank",   
    'Alignment': "Blank",
    'Age' : [0,""],     
    'HD' : (0, 0),            
    'HP' : 0,
    'ThiefChance' : (0,0,0,0,0,0),
    'Attack': (0,0),
    'Defense': {
        'AC': [10,0,0,0],
        'Saves': (0,0,0,0,0),
            },
    'XpBonus': 0, 
    'Gold': 0,
    'Languages': "None",
    'WeaponProfs': [],
    }
I'm using the dictionary like this:

code:
if Player['Race'].RaceSaveBonus is True:
    Player['Defense']['Saves'][2] = (Player['Defense']['Saves'][2] - int(Player['Stats']['CON']['Base'] / 3.5))
    Player['Defense']['Saves'][4] = (Player['Defense']['Saves'][4] - int(Player['Stats']['CON']['Base'] / 3.5))
it works, but I don't know what's wrong and what's right and I'm starting to feel like I need to re-write the whole thing

tbh the constant nagging feeling that i'm doing it wrong makes programming really discouraging :(

Mirthless fucked around with this message at 15:30 on Jul 5, 2017

Space Kablooey
May 6, 2009


I think your case right now is a really good starting point for learning about classes! Unfortunately I don't have a suitable beginner guide on those on hand right now, but you could just google "classes in python" or something like that and start from there.

Also:

Mirthless posted:

tbh the constant nagging feeling that i'm doing it wrong makes programming really discouraging :(

Whenever you get that "There has to be a better way of doing this" feeling, you should reach out and ask. Especially if you just starting out programming.

Space Kablooey fucked around with this message at 15:38 on Jul 5, 2017

Eela6
May 25, 2007
Shredded Hen
Learning to program is an iterative process. You're constantly going to go back to code you wrote a month ago and shudder at the quality of the code you wrote then - it's a natural part of the process. It's good to want to improve your code, but don't stress out too much. Every single good programmer was once a terrible programmer.

There's no single answer as to how best to structure your code. What is best depends on context. However, generally speaking, deeply nested dictionaries are a 'code smell' - it might be time to refactor and start working in classes.

Mirthless
Mar 27, 2011

by the sex ghost

HardDiskD posted:

I think your case right now is a really good starting point for learning about classes! Unfortunately I don't have a suitable beginner guide on those on hand right now, but you could just google "classes in python" or something like that and start from there.

I'm using classes already though maybe incorrectly?

I'm using functions for things like class/race selection, then returning the value to the dictionary when i call the function, like if you pick a Half-Elf Fighter or whatever the Fighter class gets assigned to Player['Class'] and the Half-Elf class gets assigned to Player['Race'] etc


code:
class Fighter(CClass):          
    HitDie = 10
    FighterCon = True
    HumanAge = 15 + (randint(1, 4))
    DwarfAge = 40 + (randint(5, 20))
    ElfAge = 130 + (randint(5, 30))
    GnomeAge = 60 + (randint(5, 20))
    HalfElfAge = 22 + (randint(3, 12))
    HalflingAge = 20 + (randint(3, 12))
    HalfOrcAge = 13 + (randint(1, 4))
    StatRequirements = 9,7,0,0,0,0
    WeaponProficiencies =  "Any weapon appropriate to size and race"
    PrimeReq = "Strength"
    ClassName = "Fighter"
    StartGold = randint(50, 200)
    WeaponSlots = 4
    NonWeapon = -2
    SaveThrows = [16, 17, 18, 20, 19]
    WeapProfs = ("Sword","Great Sword","Curved Sword",
                 "Axe","Hand Axe","Pole Arm","Mace","Flail","Monk",
                 "Club","Flail","Hammer","Mace",
                 "Morning Star","Staff","Dagger","Dart",
                 "Shortbow","Longbow","Crossbow","Spear",
                 "Lance","Javelin","Sling")
    ArmorProfs = ("Light", "Medium", "Heavy", "SmallShield", "BigShield")

    def __init__():
        pass
code:
class HalfElf(Race):
    Intelligence = (0, 4, 18)
    Dexterity = (0, 6, 18)
    Constitution = (0, 6, 18)
    
    Young = range(24, 40)
    Mature = range(41, 100)
    MiddleAged = range(101, 175)
    Old = range(176, 250)
    Venerable = range(251, 325)

    RaceName = "Half-Elf"
    Vision = "Infrared, 60'"
    PlaceHolderForSleepAndCharmBonus = 1
    ValidClass = "1234790"

    TC = (10, 0, 0, 0, 5, 0, 0, 0)
    def __init__(self):
        pass
    def ClassList(self):
        ClassChoices = (ccl.Fighter, ccl.Cleric, ccl.MagicUser, ccl.Thief, ccl.Ranger, ccl.Assassin)
        return ClassChoices

Eela6 posted:

Learning to program is an iterative process. You're constantly going to go back to code you wrote a month ago and shudder at the quality of the code you wrote then - it's a natural part of the process. It's good to want to improve your code, but don't stress out too much. Every single good programmer was once a terrible programmer.

There's no single answer as to how best to structure your code. What is best depends on context. However, generally speaking, deeply nested dictionaries are a 'code smell' - it might be time to refactor and start working in classes.

Thanks, that's heartening at least.

I knew I needed to learn and practice with classes more and this was all due for a rewrite anyway, back to the drawing board

Eela6
May 25, 2007
Shredded Hen
You may find this talk by Brett slatkin educational.

https://m.youtube.com/watch?v=D_6ybDcU5gc

Thermopyle
Jul 1, 2003

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

Mirthless posted:

I'm using classes already though maybe incorrectly?

I'm using functions for things like class/race selection, then returning the value to the dictionary when i call the function, like if you pick a Half-Elf Fighter or whatever the Fighter class gets assigned to Player['Class'] and the Half-Elf class gets assigned to Player['Race'] etc


code:
class Fighter(CClass):          
    HitDie = 10
    FighterCon = True
    HumanAge = 15 + (randint(1, 4))
    DwarfAge = 40 + (randint(5, 20))
    ElfAge = 130 + (randint(5, 30))
    GnomeAge = 60 + (randint(5, 20))
    HalfElfAge = 22 + (randint(3, 12))
    HalflingAge = 20 + (randint(3, 12))
    HalfOrcAge = 13 + (randint(1, 4))
    StatRequirements = 9,7,0,0,0,0

In case you don't realize this, this is going to give all your Fighter instances the same stats, but different stats each time you run your program.

The randint is just going to be added to those class attributes when the file is parsed on load, not each time the class is instantiated.

Python code:
from random import randint


class Fighter:
    HumanAge = 15 + (randint(1, 40))


class BetterFighter:
    def __init__(self):
        self.human_age = 15 + (randint(1, 40))


if __name__ == "__main__":
    fighter_ages = [Fighter().HumanAge for _ in range(100)]
    better_fighter_ages = [BetterFighter().human_age for _ in range(100)]

    print('Unique fighter ages:', len(set(fighter_ages)))
    print('Unique better fighter ages:', len(set(better_fighter_ages)))

code:
>python blah.py
Unique fighter ages: 1
Unique better fighter ages: 36

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

Mirthless posted:

Thanks, that's heartening at least.

I knew I needed to learn and practice with classes more and this was all due for a rewrite anyway, back to the drawing board

You've got a fairly complex system going on here, you need to be able to break it down into useful generic parts you can bolt together, and handy functions that hide the mechanics and make your objects easier to work with. Ideally you'll avoid repeating the same bit of work in multiple places, and you'll abstract it to a single function that everything calls with some parameters

Being able to do this takes experience, you need to spot patterns and be aware of how you can abstract them and what classes can do for you. Really you just need to dive in and try it, maybe with a simpler example (like just a human or whatever) and see how you can improve it. It won't be perfect, but realising why means you'll do better next time - That's Programming :frogbon:

And your code looks fine, you're just bumping up against the limitations of what you know and it's getting a bit complex. There has to be a better way!

Mirthless
Mar 27, 2011

by the sex ghost

Thermopyle posted:

In case you don't realize this, this is going to give all your Fighter instances the same stats, but different stats each time you run your program.

The randint is just going to be added to those class attributes when the file is parsed on load, not each time the class is instantiated.

Python code:
from random import randint


class Fighter:
    HumanAge = 15 + (randint(1, 40))


class BetterFighter:
    def __init__(self):
        self.human_age = 15 + (randint(1, 40))


if __name__ == "__main__":
    fighter_ages = [Fighter().HumanAge for _ in range(100)]
    better_fighter_ages = [BetterFighter().human_age for _ in range(100)]

    print('Unique fighter ages:', len(set(fighter_ages)))
    print('Unique better fighter ages:', len(set(better_fighter_ages)))

code:
>python blah.py
Unique fighter ages: 1
Unique better fighter ages: 36

It's being used to create a single output file so it hasn't really come up:

pre:
 - Race: Human  - Class: Fighter  - Age: 16 (Young)  - Align: Chaotic Evil 
===============================================================================
 
STR: 18(50)+Hit: 1   +Dam: 3   +Encumbrance: 1350   Open Doors: 3   BB/LG: 20 
CON: 10    Bonus HP / HD: 0    System Shock: 65    Resurrection: 70 
DEX: 14    Bonus to AC: 0    Reaction & Missile Adjustment: 0 
INT: 07    Additional Languages Known: 0 
WIS: 08    (Wisdom does not provide any bonus effects for your class) 
CHA: 10    Maximum Henchmen: 4    Loyalty Base: 0    Social Reaction Adj: 0 

===============================================================================
  HD: d10   HP: 1   Base AC: 10   With Dex: 10   With Armor: 10   Total: 10   

                             --- Saving Throws ---     
                        
         Paralyzation/Poison/Death: 16     Petrification/Polymorph: 17 
             Rod/Staff/Wand: 18     Breath Weapon: 20     Spells: 19
===============================================================================
    Weapon Proficiency Slots: 4  (mark below)   Non-Proficiency Penalty: -2 
The improved method is heading off problems I'm likely going to have later down the line when I expand the scope of the project though, and it explains why a couple of things weren't working the way I was expecting them to elsewhere in the program, so thank you, this is very helpful

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

I'll give you one tip though - those places where you're using a string literal like 'sword' or whatever? Any value you're going to reuse, add it as a constant somewhere (like SWORD = 'Sword') so you can refer to SWORD in your code for key lookups and comparisons and the like

That way you can't make a typo without python going 'hmmm dunno what a SWARD is explain yourself', whereas a typo in a string literal will pass silently and cause problems until you discover it. Also helps with refactoring like renaming (only one place to change it) and code completion

QuarkJets
Sep 8, 2008

Mirthless posted:

I'm using classes already though maybe incorrectly?

I'm using functions for things like class/race selection, then returning the value to the dictionary when i call the function, like if you pick a Half-Elf Fighter or whatever the Fighter class gets assigned to Player['Class'] and the Half-Elf class gets assigned to Player['Race'] etc


code:
class Fighter(CClass):          
    HitDie = 10
    FighterCon = True
    HumanAge = 15 + (randint(1, 4))
    DwarfAge = 40 + (randint(5, 20))
    ElfAge = 130 + (randint(5, 30))
    GnomeAge = 60 + (randint(5, 20))
    HalfElfAge = 22 + (randint(3, 12))
    HalflingAge = 20 + (randint(3, 12))
    HalfOrcAge = 13 + (randint(1, 4))
    StatRequirements = 9,7,0,0,0,0
    WeaponProficiencies =  "Any weapon appropriate to size and race"
    PrimeReq = "Strength"
    ClassName = "Fighter"
    StartGold = randint(50, 200)
    WeaponSlots = 4
    NonWeapon = -2
    SaveThrows = [16, 17, 18, 20, 19]
    WeapProfs = ("Sword","Great Sword","Curved Sword",
                 "Axe","Hand Axe","Pole Arm","Mace","Flail","Monk",
                 "Club","Flail","Hammer","Mace",
                 "Morning Star","Staff","Dagger","Dart",
                 "Shortbow","Longbow","Crossbow","Spear",
                 "Lance","Javelin","Sling")
    ArmorProfs = ("Light", "Medium", "Heavy", "SmallShield", "BigShield")

    def __init__():
        pass
code:
class HalfElf(Race):
    Intelligence = (0, 4, 18)
    Dexterity = (0, 6, 18)
    Constitution = (0, 6, 18)
    
    Young = range(24, 40)
    Mature = range(41, 100)
    MiddleAged = range(101, 175)
    Old = range(176, 250)
    Venerable = range(251, 325)

    RaceName = "Half-Elf"
    Vision = "Infrared, 60'"
    PlaceHolderForSleepAndCharmBonus = 1
    ValidClass = "1234790"

    TC = (10, 0, 0, 0, 5, 0, 0, 0)
    def __init__(self):
        pass
    def ClassList(self):
        ClassChoices = (ccl.Fighter, ccl.Cleric, ccl.MagicUser, ccl.Thief, ccl.Ranger, ccl.Assassin)
        return ClassChoices
Thanks, that's heartening at least.

I knew I needed to learn and practice with classes more and this was all due for a rewrite anyway, back to the drawing board

It looks like your Fighter class defines ages for various Races. It might be better if a single Age value is defined under CClass (because all characters should have an age), and then Fighter and Race can modify it, maybe using if statements to check the race and class type and then adjusting age appropriately.

Eela6
May 25, 2007
Shredded Hen

QuarkJets posted:

It looks like your Fighter class defines ages for various Races. It might be better if a single Age value is defined under CClass (because all characters should have an age), and then Fighter and Race can modify it, maybe using if statements to check the race and class type and then adjusting age appropriately.

To be more specific, you probably want to factor this out into a function something like this:

Python code:

class Fighter(CClass):
     starting_ages = {Human: (15, 1, 4)
                  Dwarf: (40, 5, 20)
                  ...}
     @classmethod
     def starting_age(cls, race):
          base, low, high = cls.starting_ages[race]
          return base+random.randint(low, high)

     def __init__(self, name: str, race: Race):
         self.name = name
         self.race = race
         self.age = self.starting_age(race)

Eela6 fucked around with this message at 21:50 on Jul 5, 2017

FoiledAgain
May 6, 2007

Mirthless posted:

pre:
 - Race: Human  - Class: Fighter  - Age: 16 (Young)  - Align: Chaotic Evil 
===============================================================================
 
STR: 18(50)+Hit: 1   +Dam: 3   +Encumbrance: 1350   Open Doors: 3   BB/LG: 20 
CON: 10    Bonus HP / HD: 0    System Shock: 65    Resurrection: 70 
DEX: 14    Bonus to AC: 0    Reaction & Missile Adjustment: 0 
INT: 07    Additional Languages Known: 0 
WIS: 08    (Wisdom does not provide any bonus effects for your class) 
CHA: 10    Maximum Henchmen: 4    Loyalty Base: 0    Social Reaction Adj: 0 

===============================================================================
  HD: d10   HP: 1   Base AC: 10   With Dex: 10   With Armor: 10   Total: 10   

                             --- Saving Throws ---     
                        
         Paralyzation/Poison/Death: 16     Petrification/Polymorph: 17 
             Rod/Staff/Wand: 18     Breath Weapon: 20     Spells: 19
===============================================================================
    Weapon Proficiency Slots: 4  (mark below)   Non-Proficiency Penalty: -2 

I don't have any comments about your code, I just wanted to say it's awesome to see a AD&D 2nd edition character sheet. That's my favorite edition, and writing a character generator for it in QBasic was my first "big" programming project way back in high school.

Boris Galerkin
Dec 17, 2011

I don't understand why I can't harass people online. Seriously, somebody please explain why I shouldn't be allowed to stalk others on social media!
In PyCharm how do I tell it to do the "optimize imports" thing but also to ignore specific lines? Basically I need to keep

code:
import os, sys
sys.path.insert(0, some_path)
as the top first two lines in some of my scripts before any other imports happen.

e:

Also how do I configure the logging module to log an output only from the root process? I run my scripts with eg

code:
mpiexec -np 24 python3 pythonscript.py
and so this creates 24 lines for every single message I log, which is really not ideal. The only true option I've been able to find is to explicitly check if rank == 0 before writing a log message but surely there must be a better way?

Boris Galerkin fucked around with this message at 13:36 on Jul 6, 2017

huhu
Feb 24, 2006
I've been using a script for a while now to launch my flask apps in debug mode.
code:
application.run(host=HOST, port=PORT, debug=True)
All of a sudden I started getting the following error:
code:
  File "C:\Python27\lib\logging\handlers.py", line 77, in emit
    self.doRollover()
  File "C:\Python27\lib\logging\handlers.py", line 350, in doRollover
    os.rename(self.baseFilename, dfn)
WindowsError: [Error 32] The process cannot access the file because it is being used by another process
Logged from file perfTimer.py, line 29
I eventually stumbled upon this solution:

quote:

I got the same error while developing a flask application. To solve the problem, I had to change the environmental variable from "FLASK_DEBUG=1" to "FLASK_DEBUG=0". The reason being that turning debugging on leads to threading errors. I got the solution after reading this blog

Where "this blog" points to http://azaleasays.com/2014/05/01/django-logging-with-rotatingfilehandler-error/ Any ideas what might have triggered this error to start popping up?

Thermopyle
Jul 1, 2003

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

Boris Galerkin posted:

In PyCharm how do I tell it to do the "optimize imports" thing but also to ignore specific lines? Basically I need to keep

code:
import os, sys
sys.path.insert(0, some_path)
as the top first two lines in some of my scripts before any other imports happen.


I seemed to recall seeing an issue on their issue tracker, and a quick search revealed my memory was correct! So, to answer your question: you vote for this issue.

As an aside, generally I've found JetBrains to be fairly responsive to their issue tracker if you write good issues.

Methanar
Sep 26, 2013

by the sex ghost
Is there any easy way to change some simple json to ini format? I can't find anything, but I'd like to avoid having to try and figure out how to roll my own converter if necessary.
code:
{
  "key1": [
    "value1",
    "value2",
    "value3"
  ],
  "key2 ": [
    "value4
    "value5"
  ]
}
to
code:
[key1]
value1
value2
value3

[key2]
value4
value5

QuarkJets
Sep 8, 2008

Look into the json and ConfigParser modules, there should be relatively little required modification (or maybe even no required modification) to the dictionary that you get from json in order for ConfigParser to write out the INI file that you want

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

^^^ or if there's a library, hell yeah. I always forget about dictionaries :shobon:

Does the structure vary or get more complex than that? If it's just a bunch of objects holding arrays you might as well just do a keys, values for loop

Methanar
Sep 26, 2013

by the sex ghost
Got it working, thanks for the suggestion.

The important bit
code:
            ini = open(self.ini_path, 'w')
            for key,val in groups.iteritems():
              ini.write('[' + key + ']')
              ini.write('\n')
              ini.write('\n'.join(val))
              ini.write('\n')
            ini.close()
I'm sure this is garbage code, but it works.

QuarkJets
Sep 8, 2008

Methanar posted:

Got it working, thanks for the suggestion.

The important bit
code:
            ini = open(self.ini_path, 'w')
            for key,val in groups.iteritems():
              ini.write('[' + key + ']')
              ini.write('\n')
              ini.write('\n'.join(val))
              ini.write('\n')
            ini.close()
I'm sure this is garbage code, but it works.

It's fine code but I'd have written it like this:

code:
	with open(self.ini_path, 'w') as ini:
		ini.write('[{key_name}]\n{val_names}\n'.format(
				key_name=key, 
				val_names='\n'.join(val)))
but with better indentation (4-spaces instead of whatever the forums is expanding tab to)

Philip Rivers
Mar 15, 2010

So here's a quick question, I got a bunch of nodes connected in a graph and I wanna store info and the chirality of those connections. Is there a pretty/Pythonic way I could assemble/sort lists by chirality?

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

QuarkJets posted:

It's fine code but I'd have written it like this:

code:
	with open(self.ini_path, 'w') as ini:
		ini.write('[{key_name}]\n{val_names}\n'.format(
				key_name=key, 
				val_names='\n'.join(val)))
but with better indentation (4-spaces instead of whatever the forums is expanding tab to)

You can do this too

Python code:
with open(self.ini_path, 'w') as ini:
    for k, v in json.items():
        print(k, *v, sep='\n', end='\n\n', file=ini)
f-strings are nice too but apparently you can't have backslashes in the expressions, so no one-liner with "\n".join(v) :ohdear:

Eela6
May 25, 2007
Shredded Hen

Philip Rivers posted:

So here's a quick question, I got a bunch of nodes connected in a graph and I wanna store info and the chirality of those connections. Is there a pretty/Pythonic way I could assemble/sort lists by chirality?

If you just want to sort the list once, that's easy as pie:

Python code:
nodes = sorted(nodes, key = lambda node: node.chirality)
If, on the other hand, you'd like to maintain a sort by chirality, I recommendf the sortedcontainers module.

Python code:
nodes = sortedcontainers.SortedListWithKey(nodes, key=lambda node: node.chirality)
nodes.add(node) #insert a new node while maintaining the sort

Eela6 fucked around with this message at 01:53 on Jul 7, 2017

Philip Rivers
Mar 15, 2010

To clarify, the nodes themselves don't have a chirality, the connecting edges have a chirality (e.g. which node would I get to next if I followed the left hand or right hand rotation).

shrike82
Jun 11, 2005

is there a rule of thumb for deciding whether to use the fork or forkserver method for spawning processes when using the multiprocessing library?
i'm noticing a 2x speed differential depending on the workload, and it's not consistently one method over the other.

accipter
Sep 12, 2003

Boris Galerkin posted:

Well I just had a frustrating time figuring out what was wrong with a part of my code when it turns out it was numpy being weird.

So I have a numpy array where some values are inf and some values are nan. I create a Boolean list of where these values in the array are inf/nan, and then I use these indices to do something to another array.

Like so:

code:
import numpy as np

a = np.array([1, np.sqrt(-1), np.nan, np.inf])  # [1, nan, nan, inf]

print(a == np.inf)
# F, F, F, T, as expected

print(a == np.nan)
# F, F, F, F, which is wrong

print(np.isnan(a))
# F, T, T, F
Is there a reason it does this? Does np.nan has an actual numerical value or something? I would have thought it would be treated in the same way as None where it just "is" or "isn't."

code:
In [6]: type(np.nan)
Out[6]: float
See this for more information: https://docs.scipy.org/doc/numpy-1.13.0/user/misc.html

Boris Galerkin
Dec 17, 2011

I don't understand why I can't harass people online. Seriously, somebody please explain why I shouldn't be allowed to stalk others on social media!

Thermopyle posted:

I seemed to recall seeing an issue on their issue tracker, and a quick search revealed my memory was correct! So, to answer your question: you vote for this issue.

As an aside, generally I've found JetBrains to be fairly responsive to their issue tracker if you write good issues.

Thanks. I voted for it but I'm not so hopeful that it'll get fixed/added since this issue has apparently been raised since 2013. I'll just have to be careful and change my workflow a bit: untick the "optimize imports" feature in the VCS commit menu and instead just manually hitting "optimize imports" when I finish editing a file/when I remember.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
Has anybody noticed quirks opening a local server socket on a work laptop using VPN? This works on VPN but hangs on the WAN:

code:
            serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            hostname = socket.gethostname()
            serversocket.bind(("", port))
            serversocket.settimeout(self.timeout)
            serversocket.setblocking(True)
            self.log.info("About to block and listen")
            serversocket.listen(1)
It could be the client test code too, I will grant that...

onionradish
Jul 6, 2006

That's spicy.
I'm trying to set up testing for a class that used to be a namedtuple. Previous tests could simply compare equality of the namedtuples:

Python code:
# Testing namedtuples with pytest
def test_data_thing():
    # return a MyCustomThing namedtuple from data
    result = module.make_mycustomthing(data)

    # create namedtuple with expected values for comparison
    expected = module.MyCustomThing(a='a', b='b')

    # compare values of the MyCustomThing namedtuples
    assert result == expected
Now that MyCustomThing is a class, that won't work. The class also now has private attributes that shouldn't be compared.

I've added a method to dump out public attributes as a dict and compare against that, which works, but I'm not sure that's the right solution. Is there a better or 'best practices' way set up the class or my tests to compare the values that matter? I could write separate tests for each attribute, but that seems worse and will needlessly increase the number of tests.

Python code:
# Testing class attributes with pytest
MyCustomThing:
    ...
    def as_dict(self):
        """Export public vars as dict for testing"""
        d = dict(vars(self))
        return {k:v for k, v in d.items() if not k.startswith('_')}
    
def test_data_thing():
    # get a MyCustomThing instance from data
    result = module.MyCustomThing(data)

    # create dict with expected values for comparison
    expected = dict(a='a', b='b')

    # compare values of the MyCustomThing instance attributes
    assert result.as_dict() == expected

Eela6
May 25, 2007
Shredded Hen
You want to implement the magic method __eq__.

__eq__ is implemented like this:

Python code:
def __eq__(self, other):
    # return true if you know how to compare the two and self should == other
    # return false if you know how to compare the two and self should != other
    # return NotImplemented otherwise (this is a fallback that allows for further extension).
Here's how the interpreter actually uses the operator ==.


Python code:
def equals_op(a, b):
    try:
        f_result = a.__eq__(b)
        if f_result is not NotImplemented:
            return f_result
    except LookupError: # a does not implement __eq__
        pass

    try:
        b_result = b.__eq__(a)
        if b_result is not NotImplemented:
            return b_result
    except LookupError: # b does not implement __eq__
        pass
    return a is b

here's an example.

Python code:

class Person:
    def __init__(self, name):
        self.name = name



class Hero:
    def __init__(self, name, secret_identity):
        self.name = name
        self.secret_identity = secret_identity

    def __eq__(self, other):
        if not issubclass(type(other), Person):
            return NotImplemented
        return self.secret_identity == other.name

clark_kent = Person('clark kent')
superman = Hero(name='Superman', secret_identity= 'clark kent')

assert clark_kent == superman
assert superman == superman
assert clark_kent == clark_kent


Eela6 fucked around with this message at 21:03 on Jul 21, 2017

onionradish
Jul 6, 2006

That's spicy.
I'd considered __eq__, and actually used it during the "upgrade" from the namedtuple to the class. Then, once the class __init__ changed, that broke and I needed to rethink. (I've been looking at the code for too long, so likely not thinking clearly.)

Is something like this a reasonable implementation to enable the comparison of the attributes? It works, but does it "smell"?
Python code:
class MyCustomThing:
    def _public_attribs(self):
        return {k:v for k,v in vars(self).items() if not k.startswith('_')}

    def __eq__(self, other):
        """Test equality with same type or dict"""
        if isinstance(other, self.__class__):
            return self._public_attribs() == other._public_attribs()
        elif isinstance(other, dict):
            return self._public_attribs() == other
        else:
            return False  # MARTHA!!!

onionradish fucked around with this message at 21:55 on Jul 21, 2017

Eela6
May 25, 2007
Shredded Hen

onionradish posted:

I'd considered __eq__, and actually used it during the "upgrade" from the namedtuple to the class. Then, once the class __init__ changed, that broke and I needed to rethink. (I've been looking at the code for too long, so likely not thinking clearly.)

Is something like this a reasonable implementation to enable the comparison of the attributes? It works, but does it "smell"?

I'm fine with it, but I like dynamic magic. I would make the following changes

Python code:
class MyCustomThing:
    def _public_attribs(self):
        return {k:v for k,v in vars(self).items() if not k.startswith('_')}

    def __eq__(self, other):
        """Test equality with same type or dict"""
        if isinstance(other, MyCustomThing): #cleaner handling of subclassing
            return self._public_attribs() == other._public_attribs()
        elif isinstance(other, dict):
            return self._public_attribs() == other
        else:
            return NotImplemented #fall through in case the other thing has a more permissive __eq__
You could also get real fancy with duck typing and specify a contract instead.
Python code:
    def __eq__(self, other):
        """Test equality with same type or dict"""
        if hasattr(other, "_public_attribs"): #fufills contract
            return self._public_attribs() == other._public_attribs()
        elif isinstance(other, dict):
            return self._public_attribs() == other
        else: 
            return NotImplemented
A part of me really likes this solution.

If you want to go crazy, you can do this:
Python code:


class MyCustomThing:
    def __init__(self, a, b):
        self.a, self.b = a, b

    @property 
    def _public_attribs(self):
        return {k:v for k,v in vars(self).items() if not k.startswith('_')}

    def __eq__(self, other):
        """Test equality with dicts or others specifying _public_attribs contract"""
        return self._public_attribs == other
IN:
Python code:

superman = MyCustomThing("foo", "bar")
batman = MyCustomThing("foo", "bar")
aquaman = {"a": "foo", "b": "bar"}
steve = {"a": "steve"}

heroes = {'superman': superman, 'batman':batman, 'aquaman':aquaman, 'steve': steve}
for keya, heroa in heroes.items():
    for keyb, herob in heroes.items():
        print(f'{keya}=={keyb}: {heroa==herob}')
OUT:
code:
superman==superman: True
superman==batman: True
superman==aquaman: True
superman==steve: False
batman==superman: True
batman==batman: True
batman==aquaman: True
batman==steve: False
aquaman==superman: True
aquaman==batman: True
aquaman==aquaman: True
aquaman==steve: False
steve==superman: False
steve==batman: False
steve==aquaman: False
steve==steve: True

Eela6 fucked around with this message at 22:57 on Jul 21, 2017

Adbot
ADBOT LOVES YOU

onionradish
Jul 6, 2006

That's spicy.
Ooo .. I like the contract version! Thanks!

EDIT: Why return NotImplemented vs. raise NotImplementedError()?

onionradish fucked around with this message at 22:44 on Jul 21, 2017

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply