5
\$\begingroup\$

This code is supposed to be the "user" system for my app. This will ask you what you want to do...

If you want to add a user, remove a user or check the list of saved users. With this I learned how to open and edit text files. And my goal doing projects is keep on learning and maybe someday I will be able to work or professionally use Python.

This code is working at the moment, but I wanted to know if is too basic or too complicated with some more professional eyes on it (please consider my 3 weeks knowledge).

snames = list()
f_n = (open('names.txt')).read()
print("Welcome to NAME.app")
##################    USER   LOGG IN        #######################
while True:
    name = input("\n - Insert name to logg in \n - ADD to save new user \n - LIST to see saved users \n - REMOVE to delete a user \n - EXIT to finish \n ...")
    if name.lower() == "add":
        n_input = input("Name:")
        with open('names.txt', 'a') as f:
            f.write(n_input + '\n')
            f.close()
        continue

    elif name.lower() == "list":
        with open('names.txt') as f:
            print(f.read().splitlines())

    elif name in f_n:
        print("Logged as", name.upper())
        nxt = input('Welcome, press enter to continue \n')
        if nxt == '':
            break

    elif name.lower() == 'remove':
        rem = input("Insert user name to remove \n ...")
        with open('names.txt', 'r+') as f:
            l=f.readlines()
            l=[z for z in l if rem not in z]
        with open('names.txt', 'w') as f:
            f.writelines(l)


    elif name.lower() == "exit":
        exit()
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Why not convert name to it's lower equivalent before testing it. name = name.lower() \$\endgroup\$ – theProgrammer Dec 2 '20 at 0:44
  • 1
    \$\begingroup\$ That's true, what would you rather. read the code and have every .lower() in each place or name = name.lower(). For me was much better to put it on every single place to I would know what's doing (better readability) But maybe I'm wrong and people prefer as you put it!! Let me know. \$\endgroup\$ – Alejandro Trinchero Dec 2 '20 at 13:26
0
\$\begingroup\$

Here is the review:


  1. Always use with when opening a file, there are no exceptions. If you use .read(), when the user enters, for example, "Jan", while the names.txt file doesn't have has "Jan", but has "Jannet", the program will still return True for "Jan" in f_n. You can fix the problem using .splitlines() instead:
f_n = (open('names.txt')).read()

to

with open('names.txt', 'r') as r:
    f_n = r.read().splitlines()

  1. You can drastically improve the readability of a multi-line string using triple-quotes.
menu = "\n - Insert name to logg in \n - ADD to save new user \n - LIST to see saved users \n - REMOVE to delete a user \n - EXIT to finish \n ..."

to

menu = """\
- Insert name to log in
- ADD to save new user
- LIST to see saved users
- REMOVE to delete a user
- EXIT to finish
... """

  1. You do not need to assign an input statement to a variable in order for it to pause the program until the user presses ENTER.
nxt = input('Welcome, press enter to continue \n')
if nxt == '':
    break

to

input('Welcome, press enter to continue \n')

  1. Since the continue isn't necessary, as none of the elif statements will execute if the program reaches that point anyway. Also, there is no need to use .close(), as the file handler does it for you:
    if name.lower() == "add":
        n_input = input("Name:")
        with open('names.txt', 'a') as f:
            f.write(n_input + '\n')
            f.close()
        continue

to

    if name.lower() == "add":
        n_input = input("Name:")
        with open('names.txt', 'a') as f:
            f.write(n_input + '\n')

  1. You can increase the efficiency of your code by directly iteration through a given generator, instead of turning the generator into a list first. To detect whether two strings are equal or not, using the not in operator is prone to cause bugs. For example, 'Bob' not in 'Bobble' returns False, but they are different strings. Instead, use the != operator, as 'Bob' != 'Bobble' returns True:
    elif name.lower() == 'remove':
        rem = input("Insert user name to remove \n ...")
        with open('names.txt', 'r+') as f:
            l = f.readlines()
            l = [z for z in l if rem not in z]
        with open('names.txt', 'w') as f:
            f.writelines(l)

to

    elif name.lower() == 'remove':
        rem = input("Insert user name to remove \n ...")
        with open('names.txt', 'r+') as f:
            l = [z for z in f if z != rem]
        with open('names.txt', 'w') as f:
            f.writelines(l)

Altogether:

snames = list()
with open('names.txt', 'r') as r:
    f_n = r.read().splitlines()

print("Welcome to NAME.app")
menu = """\
- Insert name to logg in
- ADD to save new user
- LIST to see saved users
- REMOVE to delete a user
- EXIT to finish
... """

##################    USER   LOGG IN        #######################
while True:
    name = input(menu)
    if name.lower() == "add":
        n_input = input("Name:")
        with open('names.txt', 'a') as f:
            f.write(n_input + '\n')
    elif name.lower() == "list":
        with open('names.txt') as f:
            print(f.read().splitlines())
    elif name in f_n:
        print("Logged as", name.upper())
        input('Welcome, press enter to continue \n')
    elif name.lower() == 'remove':
        rem = input("Insert user name to remove \n ... ")
        with open('names.txt', 'r') as f:
            l = [z for z in f if z != rem]
        with open('names.txt', 'w') as f:
            f.writelines(l)
    elif name.lower() == "exit":
        exit()

```
\$\endgroup\$
4
  • \$\begingroup\$ 1- Using always 'with' is something for the functionality or just for easier reading. Splitlines sounds great! didn't know that thank you. 2- I was looking for ages how to write the menu like that in the text editor. I was annoying even for me. 3- Why should I get rid of the break? I suppose is because I didn't show the second part that it's a second while loop. 4- It is now better if I close and open the file to avoid problems with saving and loading new data in the file? as I'm using the same file for all the functions in the main menu. \$\endgroup\$ – Alejandro Trinchero Dec 2 '20 at 12:52
  • \$\begingroup\$ 5- I see your point of getting rid of Not in, but that is the only way that my code would work tried all different sorts of codes but that's the only functional. \$\endgroup\$ – Alejandro Trinchero Dec 2 '20 at 13:00
  • \$\begingroup\$ @AlejandroTrinchero 1- Using with is much safer, and it closed the file for us. 2- Great! 3- Oh, there's a second part? Here at Code Review we expect to be given the full working code. 4- Yes. Again, the with open statement closes it for you. 5- That's funny... perhaps in one of the strings you have a trailing whitespace? Try printing f (and maybe also rem) to see if there are any strings with a trailing whitespace. \$\endgroup\$ – Chocolate Dec 2 '20 at 13:08
  • \$\begingroup\$ Yes, sorry about that, but I didn't even start the second part so I didn't want to say anything:). That's great didn't know that with open as well closed the file. I'll keep on trying with the != because it's true is much better, and as well I might learn how to use it properly haha. TY! \$\endgroup\$ – Alejandro Trinchero Dec 2 '20 at 13:21
2
\$\begingroup\$

First thing I notice is that this...

nxt = input('Welcome, press enter to continue \n')
if nxt == '':
    break

...could just be:

input('Welcome, press enter to continue')

It doesn't seem like you're using nxt for anything else so there's no need to store a value for it, especially if you just want the user to hit enter.


Next, you never do f_n.close() which can cause some issues with the file (e.g., it doesn't save or something weird happens with the garbage collector system, etc.).

You might want to replace...

elif name.lower() == "exit":
    exit()

...with:

elif name.lower() == "exit":
    f_n.close()
    exit()

The same should be done with the file in the first elif. Something I also noticed about this is that f_n is the same file as f. You shouldn't need to keep opening it; just use the f_n variable.


Instead of...

if name.lower() == "add":
    n_input = input("Name:")
    with open('names.txt', 'a') as f:
        f.write(n_input + '\n')
        f.close()
    continue

...with:

if name.lower() == "add":
    n_input = input("Name:")
    with open('names.txt', 'a') as f:
        f.write(n_input + '\n')
        f.close()

You don't need to say continue because the rest of the while loop is just elifs.


In terms of overall code style, mostly good, but there are a few things you might want to keep in mind:

  1. Put spaces around equals signs for readability (e.g., use n = 10 instead of n=10).
  2. It's spelled "log" not "logg."
  3. I don't see a usage of snames, so is it really necessary?
  4. The first comment in your code looks rather odd. Maybe just say # USER LOGIN , use a simple block comment, or, if you have to:
##############
# USER LOGIN #
##############

Hope this helps! If I think of something else, I'll edit it in.

\$\endgroup\$
8
  • \$\begingroup\$ That's great thank you very much! \$\endgroup\$ – Alejandro Trinchero Dec 2 '20 at 12:10
  • \$\begingroup\$ That's great thank you very much! 1- I notice that I can get rid of the "Nxt" variable nothing changes. As you said is useless. But if I get rid of "Break" the program won't leave the first menu into the second, I need that break to exit the first While loop and jump straight into the second. 2- I don't really understand your second point. f_n is a variable just made to open and read the file. while f is just the way everybody uses "With open('...') as f". If I would like to get rid of f_n variable how would I replace it? In for example: Elif name in f_n: This really helped TY!! \$\endgroup\$ – Alejandro Trinchero Dec 2 '20 at 12:28
  • \$\begingroup\$ You don't need to use with open() as f. You can just refer to f_n without making a new variable f. \$\endgroup\$ – Voldemort's Wrath Dec 2 '20 at 15:09
  • \$\begingroup\$ @AlejandroTrinchero -- Essentially, you're opening the same file multiple times which is not necessary. The lines that you have inside your with open() as f can just be outside the with and use the variable f_n instead of f. \$\endgroup\$ – Voldemort's Wrath Dec 2 '20 at 15:10
  • 1
    \$\begingroup\$ @AlejandroTrinchero -- Yes, the first reason. Maybe even just get rid of f_n and use the file as you do in the rest of your code. \$\endgroup\$ – Voldemort's Wrath Dec 2 '20 at 21:24
1
\$\begingroup\$

Code after the opinions. Thank you very much for taking the time, I understand most of your points which makes me happy that I'm not too lost. Soon second part of my project another menu.

   with open('names.txt', 'r') as r :
    f_n = r.read().splitlines()
print("Welcome to NAME.app")
##############
# USER LOGIN #
##############
while True:
    name = input("""
    \n - Insert name to logg in
    \n - ADD to save new user
    \n - LIST to see saved users
    \n - REMOVE to delete a user
    \n - EXIT to finish
    \n - ...""")

    name = name.lower()

    if name == "add":
        n_input = input("Name:")
        with open('names.txt', 'a') as f:
            f.write(n_input + '\n')
            f.close()

    elif name == "list":
        with open('names.txt') as f:
            print(f.read().splitlines())
            f.close()

    elif name in f_n:
        print("Logged as", name.upper())
        input('Welcome, press enter to continue \n')
        break

    elif name == 'remove':
        rem = input("Insert user name to remove \n ...")
        with open('names.txt', 'r+') as f:
            l = f.readlines()
            l = [z for z in l if rem not in z]
        with open('names.txt', 'w') as f:
            f.writelines(l)

    elif name == "exit":
        r.close()
        exit()
  • Removed NXT variable kept break to jump into next loop, second part of project.
  • Added .close() to files to avoid problems saving, etc.
  • Removed useless pieces of code that were left during building.
  • Added .splitlines() to improve the accuracy of the users log in. And changed open for with open.
  • Checked spaces between code like x=x and fixed readability.
  • Changed name.lower() on every elif for name = name.lower()

Again thank you very much for the patience and help.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ That's great! Don't forget to select one answer to click on the checkmark to close this case :) \$\endgroup\$ – Chocolate Dec 2 '20 at 13:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.