site banner

Small-Scale Question Sunday for April 21, 2024

Do you have a dumb question that you're kind of embarrassed to ask in the main thread? Is there something you're just not sure about?

This is your opportunity to ask questions. No question too simple or too silly.

Culture war topics are accepted, and proposals for a better intro post are appreciated.

1
Jump in the discussion.

No email address required.

Does anybody like programming?

I have been hired as a sole and lead Python developer in a company. But my Python experience is mostly on Numpy, if anybody has some tips? It would be very appreciated!

Partly a response, partly hijacking this to ask a question of my own to everyone else: what are you using as a editor/compiler?

I programmed exclusively in Java for years, but my new boss wanted programs in Python so I've been doing that this past year. Using Eclipse, which is wonderful as an editor, since it lets me organize everything and highlights typos that I make and stuff.

Aside a whole lot of friction involving different conventions and abilities, I was annoyed that all of the Python editors people recommended seemed way less functional until I discovered that I can program Python in Eclipse if I do the right stuff. So I've been doing that.

I'm not sure what the general consensus is, because I'm mostly self-taught and program on my own, making mathematical models for research purposes that nobody else has to use or collaborate with, so I've probably got all sorts of weird habits that would make more sophisticated programmers cringe. So I can't tell how much of this is objective and how much is just me being used to Eclipse for so many years and having little experience with anything else. But I tentatively recommend looking into PyDev for Eclipse, because in my opinion it's nice.

Yeah, seconding both prongs, here: a) IDEs are important and b) Python IDEs near-universally suck. If you're in the Java sphere before, PyCharm is kinda the Intellij-for-Python, for better and worse, and there's a large faction that loves VSCode for eating all of their RAM handling multi-language projects reasonably, but for the love of god don't try to build class-ful python in IDLE.

((I'll generally advocate PyCharm for new programmers, as annoying some of the Intellijisms can be, but if you're more acclimatized to and have already set up Eclipse it's definitely not worth swapping.))

Do you know if there's a way to.... I'm not even sure what the right language is here.... put different classes in different .py files, or at least different tabs, without running into recursive dependency issues.

Like, in Java, I can make a World class that contains a population from the Agent class, and models an epidemic going through them, and the Agents have a bunch of methods internally regarding how they function as they get infected and recover and stuff. And if I pass a copy of the main World to each Agent when it's created, then when they do stuff in their methods they can call back up to the World, usually for counting purposes, they say "hey I got infected, increment the total infection counter" or "hey someone was going to infect me but I'm already infected, increment the redundant infection counter".

As far as I can tell, in Python I can't do that nicely. If the World class imports Agent, then the Agent class can't import World. I can resolve this by defining both classes in the same .py file, but then all my code is arranged 1-dimensionally and I have to scroll through tons of stuff to find what I'm looking for (or use ctlr F). Whereas in Java each class has its own tab, I can open or close or switch to, so well-behaved ones that I'm not working on don't take up space or get in my way. I'm not sure if this is a Python issue or just a Eclipse issue. Is there a way to split a .py file into multiple tabs so I can organize better?

I'm... not very good with Python, but my understanding, a toy example would be :

main,py:

import agent
import world

agentCount = 20
infectionCount = 25
world = world.World()
print("Starting...")
for i in range(agentCount):
    world.addAgent(agent.Agent(world))

for i in range(infectionCount):
    world.infectRandomAgent()

print("Total Infections :" + str(world.totalInfections))
print("Total Redundant Infections :" + str(world.redundantInfections))
for i in range(agentCount):
    print("Agent #" + str(i) + " Infections:" + str(world.knownAgents[i].countedInfections))

world,py:

import random

class World:
    knownAgents = list()
    totalInfections = 0
    redundantInfections = 0

    def addAgent(self, newAgent):
        self.knownAgents.append(newAgent)

    def infectRandomAgent(self):
        random.choice(self.knownAgents).incrementInfection()

agent,py:

class Agent:
    wasInfected = False
    countedInfections = 0

    def __init__(self, ownerWorld):
        self.world = ownerWorld

    def incrementInfection(self):
        self.world.totalInfections += 1
        if self.wasInfected:
            self.world.redundantInfections += 1
        self.wasInfected = True;
        self.countedInfections += 1

Note that if you're using raw python3.exe or a basic IDE like IDLE, all three files will need to be in the same folder, or you have to treat them like modules. Better IDEs like PyCharm will handle most of this for you, though I'd recommend experimenting before futzing with it a lot.

__init__ is a python builtin capability that's pretty equivalent to Java Constructors. The first argument for any class function will act as a reference to the instance of that class being called for that function, regardless of name -- do be careful getting a convention for that early and often, or it'll drive you up the walls. self is popular in pythonic circles, but I've seen a surprisingly large project that took the convention of this<className>, probably downstream of java or C# devs.

Only your main simulation file really should need to import the files that make up the actual objects. The class objects themselves don't need to know about each other, even if they're calling methods or fields specific to the other class, because that gets looked up during live runtime operations.

(edit: specifically, the class calling the constructor for an instance of an object needs to import that object. You could have, and it would probably be cleaner, to import Agent within world.py and not from within main.py, and do the agent constructor in the form :

    def addAgent(self):
        self.knownAgents.append(agent.Agent(self))

But I've been burned before in python environments where I ended up with my class imports spread throughout for hundred places and it being a nightmare to refactor or rename or handle versioning, so my preference for non-giant projects is to centralize imports, and for giant python projects you probably should be breaking it into modules.

I've been doing it like that, where they're all together and reference each other, it's just that then when Agent has 15 methods because some of them are experimental variations on each other or niche things I wanted to do to see what would happen, then I make another class for graphing scatter plots, and I've got a bunch of methods for (Make a world, then modifier the parameters according to X, then execute Y, then graph the results, then repeat that N times) that would be nice to stick in their own class somewhere, and then I've got a bunch of useful static methods that do stuff like load and save data to CSVs that would be nice to have in their own class for organization purposes. And if I just lay them out linearly (which I mostly have, with a few rare exceptions that definitely have 0 recursive dependencies and I actually have moved them to their own .py file) then I have literally 2000 lines of code I have to scroll up and down just to find the right class whenever I want to check to see what the name of the method I want to call is or something, and then scroll back down to find the spot I'm working on.

There's nothing like the partial class concept from C#, though I agree it would be really nice if there were.

You can kinda fake it by exploiting the heck of out inheritance, in a couple different ways, depending on what level of composition you're aiming to be able to do. If you want selective import of behaviors (and to avoid the diamond inheritance problem, mostly), you can do something like :

agentInfectionLogic,py:

wasInfected = False
countedInfections = 0

def incrementInfection(self):
    self.world.totalInfections += 1
    if self.wasInfected:
        self.world.redundantInfections += 1
    self.wasInfected = True
    self.countedInfections += 1

def infectedCount(self):
    return self.countedInfections

agentFileLogic,py:

def loadInfectionInfo(self):
    temploadInfections = 20
    for x in range(temploadInfections):
        self.incrementInfection()
    # do an actual file load here.

def saveInfectionInfo(self):
    tempfile = self.infectedCount
    # save an actual file here.

agent,py:

class Agent:
    from agentInfectionLogic import infectedCount, incrementInfection, countedInfections, wasInfected
    from agentFileLogic import saveInfectionInfo, loadInfectionInfo

    def __init__(self, ownerWorld):
        self.world = ownerWorld

And then calls like world.knownAgents[0].loadInfectionInfo() or world.infectRandomAgent() would work as normal, and you can even swap between different experimental forms by having from agentInfectionLogic import infectedCount, incrementInfection, countedInfections, wasInfected or from testAgentInfectionLogic import infectedCount, incrementInfection, countedInfections, wasInfected (or even a mix-and-match between the two).

Agent.py has to know about what's going on, but to everywhere else, anything imported into agent.py looks identical to as if it were coded into that file or class. Eventually this turns into a full module, where the __init__.py file holds the glue and then you have better names for your actual logic .pys, but when that makes sense depends a lot on the scale of your project.