• bennr01

    @JonB said:

    For doing 1:1 character replacements, maketrans plus translate makes for clean code. You list all the characters you are replacing in one string, all the replacements in the second, and all the characters to delete in the third argument to maketrans.

    Damn, I never knew about this. Now I can finally replace my for c in (...): s = s.replace(c, "") loops. My code may finally look acceptable.

    posted in Pythonista read more
  • bennr01

    @ccc said:

    Does anyone use Python 2 anymore?

    Please don't judge those of us who prefer the version of python closer to perfection.

    posted in Pythonista read more
  • bennr01

    @talns100 If I understand your problem correctly, you call input("Number: ") and get a string value as a return value although you had expected a string.

    This is a python2 vs python3 issue. In python2, raw_input() returned a string while ’input()evaluated the input as a python object. In py3,input()is equivalent to python2'sraw_input()`.

    To fix this, you could:

    • run the script as py2 instead (not recommended)
    • wrap the input() in a int() (int(input("Number: ")))
    • import ast and use ast.literal_eval(input("Number: ")).

    The last variant will allow inputing any value while preventing python code execution.

    posted in Pythonista read more
  • bennr01

    Pickling refers to using the pickle module for persisting data. You don't need to implement it yourself, it's included in a module by default.

    First, you can access the documentation by swiping from right to left to open the console. There you'll find a button labeld ?. Press it to open the documentation. The documentation contains a lot of explanations, how-tos and references of modules. You'll need to search for pickle, then you'll get a guide on how to use it.

    If you don't want to look it up:

    import pickle  # load the pickle module
    
    my_data = ...  # whatever you want to save
    s = pickle.dumps()  # s is now a string from which you can rebuild my_data
    with open("data.bin", "wb") as fout:  # open file 'data.bin' for binary writing
        fout.write(s)  # write string s
    # let's load it
    with open("data.bin", "rb") as fin:  # open file 'data.bin' for binary reading
        loaded_s = fin.read()  # read string from file
    loaded = pickle.loads(loaded_s)  # unpickle the string, returning a copy of my_data
    

    The above code stores some data and reloads it. You could also change the code to use pickle.dump() instead of pickle.dumps(), which is better when working with large data sets, but I think this explains it better.

    However, I don't think pickle is the go-to solution. I don't know what exactly you are attempting to save, but generally pickle should be avoided. Pickle is python specific and very flexible, but also insecure. If an attacker can modify a file containing a pickle dump, arbitrary code execution becomes possible. You should instead think about using the json module, which can't store custom classes but is still one of the most common data formats, using files directly (requires a bit more work) or using a database like anydbm or sqlite3.

    posted in Pythonista read more
  • bennr01

    @Sparky01

    I haven't tested it, but I think the problem is that you aren't using file offsets correctly. Basically, right now you are reading the file, then continue writing from the last position you have read.

    The best solution would be to seperate reading and writing the files.

    import yaml
    
    class MyClass():
      def __init__(self):
        with open('config.yml', 'r') as fin:
            self.config = yaml.load(fin)
        self.config['hi'] = 1
        self.config['hello'] = 1
        with open('config.yml', 'w') as fout:
            yaml.dump(
              self.config,
              fout,
              default_flow_style=False
            ) 
        print(self.config)
        # returns {'hi': 1, 'hello': 1} 
        
    MyClass()
    

    Alternatively, call self.configFile.seek(0) after reading. This sets the read/write offset to the beginning of the file. Be warned that this only works if the new file content has at least the same length as the original file content, otherwise trailing bytes will remain!

    posted in Pythonista read more
  • bennr01

    I think you may be confusing a few different datatypes here, so I'll try to explain some approaches for your problem.

    First of, Python does not really have something like arrays. Usually, when one wants to use something akin to an array in Python, one uses a list instead. The main difference between a list and an array is that usually arrays are fixed size and often fixed type also while Python lists can have any required size and mixed types of elements. However, you wrote "same variables", so lists may not be what you are looking for. Still, heres a short tutorial for lists:

    # create a list
    l = []  # alternatively, use "l = list()"
    # add an element to a list
    l.append(1)
    # get the size of the list
    print(len(l))
    # get the first element (index is 0 as indexes start with 0)
    print(l[0])  # prints "1"
    # remove the first element
    del l[0]  # alternatively, use "l.pop(0)", which also returns the element
    

    Now let's take a look at how lists could be used for your problem:

    # number of players
    num_players = 4
    # number of variables each player has
    num_vars = 10
    
    # initiate a two-dimensional list with all players or variables
    # a two-dimensional list is a list of lists. In this case, all "variables" will be initialized as None.
    players = [[None] * num_vars] * num_players
    
    # set 2nd variable for player 3 to 12. Remember that indexes start at 0
    players[2][1] = 12
    # get 2nd variable for player 3
    print(players[2][1])  # prints "12"
    
    # ============= alternative =============
    # using math, we can do this a bit more efficient using 1-dimensional lists
    
    # number of players
    num_players = 4
    # number of variables each player has
    num_vars = 10
    
    # initiate a one-dimensional list with all players or variables
    players = [None] * num_vars * num_players
    # now we can access a variable by using index = (player_index * num_vars + var_index)
    
    # set 2nd variable for player 3 to 12. Remember that indexes start at 0
    players[2 * num_vars + 1] = 12
    # get 2nd variable for player 3
    print(2 * num_vars + 1)  # prints "12"
    
    

    However, as I said before, lists aren't a good solution for this. Let's take a look at another datastructure, the dict. A dict is a mapping of key-value pairs. Think of it like a dictionary, where each word you look up (in this case the key) has some associated words (the value). Here is an example of a dict usage:

    d = {}  # alternatively, use "d = dict()"
    # set a key to a value
    d["name"] = "bennr01"
    # get the number of defined keys in a dict
    print(len(d))  # prints "1"
    # get a value for a key
    print(d["name]")  # prints "bennr01"
    # remove a key-value pair
    del d["name"]
    

    Using dicts, you can refer to the variables using names. Here's how to use it for your problem:

    players = []
    # create a player here
    player_1 = dict(name="Player 1", score=0)
    players.apend(player_1)
    
    # set the score for the first player (again, index 0)
    players[0]["score"] = 100
    # get the score for the first player
    print(players[0]["score"])  # prints "100"
    
    # ============= alternative ==============
    # instead of using a list for all players, you could also use a dict
    
    players = {}  # <-- see the difference
    # create a player here
    player_1 = dict(name="Player 1", score=0)
    players[1] = player_1
    
    # set the score for the first player. As we are using a dict, we do not need to start with 0. We can even use strings
    players["pl_1"]["score"] = 100
    # get the score for the first player
    print(players["pl_1"]["score"])  # prints "100"
    

    Still, what you should be looking into are classes. Classes can have attributes and methods. As a tutorial would take too long, here is how you would use them:

    
    class Player(object):
        """This class represents a player"""
        def __init__(self, name):
            self.name = name
            self.score = 0
    
        def increment_score(self):
            """Increment the score by 1. This is an example for a method."""
            self.score += 1
    
    players = []
    # create a player
    player = Player("bennr01")
    players.append(player)
    # get the name
    print(players[0].name)  # prints "bennr01"
    # increase score
    players[0].increment_score()
    # print score
    print(players[0].score)  # prints "1"
    

    You can of course combine this with lists and dicts as needed.

    posted in Pythonista read more
  • bennr01

    First of, you can move your *_patient_list into the Patient class to reduce global variables.

    class Patient(object):
        master_patient_list = []  # this should be shared among all Patients
        def __init__(self, ...):
            ...
            self.master_patient_class.append(self)
    

    Second, I think you want something like this for example:

    class Physician(Employee):
        illness2doctor = {}  # shared dict mapping illness -> doctor for illness
    
        def __init__(self, name):
             # just as example
             self.name = name
    
        @classmethod
        def register_doctor(cls, doctor, illness):
            assert not illness in cls.illness2doctor  # prevent overwrite
            cls.illness2doctor[illness] = doctor
    
        @classmethod
        def get_doctor_for(cls, patient):
            illness = patient.illness
            if illness not in cls.illness2doctor:
                raise KeyError("No doctor for illness")
            return cls.illness2doctor[illness]
    
    
    # --- usage ---
    # create a new physician
    alice = Physician(name="Alice")
    # alice can treat "Broken Leg"
    Physician.register_doctor(alice, "Broken Leg")
    
    # now we can get the doctor for patient1
    print(Physician.get_doctor_for(patient1).name)
    # -> should print "Alice"
    

    posted in Pythonista read more
  • bennr01

    [s[i:i+2] for s in a for i in range(0, len(s), 2)]

    Replace 2 with chunk length.

    posted in Pythonista read more
  • bennr01

    @trey

    You can also use six by running pip -6 install…, but I’ve found modules installed into Python 3 that way from Python 2 StaSh to be unreliable. You can import them, but sometimes they don’t work, and pip list doesn’t show them in either StaSh 2 or 3. So I just wouldn’t do it.

    -6 does not use six, it just tells pip to use the shared site-packages directory so that you can install a package for both interpreters. Some packages may distribute different files depending on the installing python version which may cause the problems. Also, since pip stores information about the installed packages within site-packages, you must specify -6 for pip show too (pip -6 show).

    posted in Pythonista read more
  • bennr01

    StaSh runs on both py2 and py3, though not all commands support py3. pip uses the python interpreter StaSh was launched with and installs the package into the version specific site-packages directory. You can use the -6 option to tell pio that it should install a package into the shared site-packages directory.

    You can force StaSh to use a specific python version by long-pressing the Run-Button and choosing the "run with python X" option.

    posted in Pythonista read more

Internal error.

Oops! Looks like something went wrong!