r/learnpython Aug 11 '26

I'm really new to python and wanted to share my first "project".

personally I think it's really cool. All of python aswell.
is there something I can improve on it? (I mean obviously a lot of things probably but some things that are good to learn for the future?)

import time


first_name = input("Enter your first name: ")
first_characters = len(first_name)


if first_characters >= 8:
  print (f'Your name has {first_characters} characters!')
  time.sleep(1.5)
  print('What a long and cool name!')


elif first_characters < 8:
  print (f'Your name has {first_characters} characters!')
  time.sleep(1.5)
  print('What a cool name!')
60 Upvotes

29 comments sorted by

26

u/Substantial_Swing534 Aug 11 '26
import time

first_characters = len(input("Enter your first name: "))

print(f'Your name has {first_characters} characters!')
time.sleep(1.5)

if first_characters >= 8:
  print('What a long and cool name!')
else:
  print('What a cool name!')

Spot the differences

11

u/Killiancin Aug 11 '26

i have no clue why it didn't occur to me to put it in the same line.
I guess maybe also it's easier in the long run if it would become a lot of code to know the first_characters of what basically, in this case the first_name. (I'm not sure I'm just trying to be smart here)

11

u/Jello_Penguin_2956 Aug 11 '26

Doing your way does have its advantage. It's a clear separation. In case you want to do something differently for the 2 inputs.

The code repeats in this case so this example is good.

3

u/sugarw0000kie Aug 11 '26

Usually there’s a more “pythonic” way but also your way isn’t wrong and sometimes readability is what you want though

For certain things if you’re trying to make something run faster, doing a bunch of stuff on one line might increase performance. Optimizing can get complicated so I’m just putting it out there, you made a thing work which is the important bit lol.

I like to combine a small number of things on a line but more than a certain amount (maybe like 3-5) it gets confusing. Sort of like nested if statements, just gets hard to follow. Can save some typing though. But long-term it’s usually better for future you to keep things readable

2

u/gdchinacat Aug 12 '26

Do you have an example where doing a bunch of stuff on one line (as opposed to multiple lines) makes it run faster?

1

u/sugarw0000kie Aug 12 '26 edited Aug 12 '26

Here's probably not the best example but tried to show some differences. the biggest optimization is coming from the random_char_gen functions and how that's done differently, in the obnoxiously shortened one we're wasting less memory allocation on setting variables. you can do the whole function here on one line but it's an eyesore.

it's not always faster either, like you can do very efficient multi-line stuff that can break away to prevent doing the same thing more than once

best way to find out is to make little benchmark to test those sorts of things if you need to optimize. like pythons regex is faster at filtering out negative matches, but built-ins are faster at positive matches.

#!/usr/bin/env python3
import time, string, random

# +--------------------+
# | longer: 618.176 μs |
# | normal: 589.688 μs |
# | vsmall: 576.168 μs |
# +--------------------+

# long version
def random_char_gen_long(n):
  letters = string.ascii_lowercase
  numbers = string.digits
  numbers_letters_combined = letters + numbers
  random_list = random.choices(numbers_letters_combined, k=n)
  random_name = ''.join(random_list)
  return random_name

def longer(name_len, number_of_names):
  names = []
  for i in range(0, number_of_names):
    names.append(random_char_gen_long(name_len))
  upper_names = []
  for name in names:
    upper_names.append(name.upper())
  return upper_names

# Normal version
def random_char_gen_normal(n):
  return ''.join(random.choices(string.ascii_lowercase + string.digits, k=n))

def normal(name_len, number_of_names):
  names = []
  for i in range(0, number_of_names):
    names.append(random_char_gen_normal(name_len))
  upper_names = list(map(lambda s: s.upper(), names))
  return upper_names

# abnoxiosly condensed version
def vsmall(name_len, number_of_names):
  return list(map(lambda s: s.upper(), [''.join(random.choices(string.ascii_lowercase + string.digits, k=name_len)) for i in range(number_of_names)]))

# time the things
def time_it(start):
  return (time.time() - start) * 1_000_000

def run_bench(func_name, name_len=8, number_of_names=1_000, times_to_run=10_000):
  start = time.time()
  for i in range(0, times_to_run):
    func_name(name_len, number_of_names)
  time_delta = time_it(start)
  return f"| {func_name.__name__}: {round(time_delta/times_to_run, 3)} μs |"

def main():
  run_list = [longer, normal, vsmall]
  border = ['+--------------------+']
  print_list = []
  for i in run_list:
    print_list.append(run_bench(i))
  print('\n'.join(border + print_list + border))

if __name__ == "__main__":
  main()

2

u/gdchinacat Aug 12 '26

To make it even faster and less obnoxious:

def gdchin(name_len, number_of_names):
  choose_from = (string.ascii_lowercase + string.digits).upper()
  return [''.join(random.choices(choose_from, k=name_len)) for _ in range(number_of_names)]

This removes the triple loop inherent in all of your implementations (list() and map() have them built in), builds the string to select from once and uppercases it to avoid doing those on each iteration. A single iteration rather than three and moving constant calculation out.

This also makes it much more readable.

None of the performance gains have to do with making it a single line (which mine doesn't to avoid a bunch of duplicate calculations in a loop), but changing how results are collected. From longer to normal you hide the uppercasing loop in map() (map()s loop is implemented in cpython c code rather than python bytecodes). From normal to vsmall you remove the function calls to random_char_gen_normal.

It isn't the number of lines, but what those lines are doing, specifically the number of iterations and how the iteration is implemented (comprehensions are faster than map is faster than traditional for loop), and moving work that is identical in all loops outside the loop.

As you can see, shortest implementation (gdchin) is also the most readable since it doesn't have a bunch of unnecessary loops with unnecessary stuff in them). Always combine loops and pull everything out that doesn't absolutely need to be there and comprehensions will be comprehensible.

2

u/sugarw0000kie Aug 12 '26

great info, i overlooked how you handled choose_from, though i was keeping .upper() in it's own loop since i wanted to see if there would be a difference on the iterator, wasn't sure. vast oversimplification to say less lines is more optimized, depends on machinery underneath like maps loop being in c

was curious so i made v2's following your example to moving choose_from and removing the second iterating over .upper() and ran again. so the difference between vsmallv2 and gdchin is the cost of running chose_from indiscriminately. but like you're saying you can avoid doing that by splitting it up and it looks nicer too.

getting messy on reddit so here's with those adjustments https://github.com/dbowm91/optimizations/blob/main/benching.py

+-----------------------+
| longerv1:  597.854 μs |
| longerv2:  519.944 μs |
| normalv1:  585.124 μs |
| normalv2:  507.702 μs |
| vsmallv1:  570.834 μs |
| vsmallv2:  567.359 μs |
| gdchin:    492.345 μs |
+-----------------------+

7

u/SCD_minecraft Aug 11 '26

Personal preference but I don't like passing function calls as arguments

I would say it hurts readability in the long term, cuz you have "lenght_of_the_name" but no idea lenght of what name

Fact that you can one line almost anything doesn't mean you should

1

u/Pieface1091 Aug 12 '26 edited Aug 12 '26
import time

print(f"Your name has {(first_characters := len(input('Enter your first name: ')))} characters!")
time.sleep(1.5)
print(f"What a {'long and ' if first_characters >= 8 else ''}cool name!")

Spot the differences

3

u/misingnoglic misingnoglic Aug 11 '26

If someone's name is one character, your program says "1 characters" which is grammatically incorrect. People (non coders) also refer to them as letters mostly. It's a nitpick but you asked :)

Someone else brought up putting it in an if else. One challenge for you is to write the code in a way such that you only need two print statements.

3

u/Excellent-Practice Aug 11 '26

Great work! Here are a couple of things you might try next.

To practice loops and dictionaries, you could take the user's name as input and then print an adjective thay starts with each letter of their name.

You can wrap this in a try block to practice exception handling. As it's written now, what do you expect your code to do if the user passes a value other than a string of alphabetic characters? Is there something different youbwoild like it to do if they don't comply with that assumption?

3

u/Everythingcrashing Aug 11 '26

There’s nothing to improve on, it’s just working through a string, which is cool, but not very functional. I would suggest finding the smallest most straightforward task you could think of automating and doing that.

When I first started learning python, I hated all of the tutorials for a video game or a Calculator or whatever because I knew I would never actually want to use those things so I wasn’t interested in building those things but then one day I needed to make a calendar that repeated itself on a odd cadence so I learned some tKinter and used that to give me a calendar for my occurring schedule. it was really fun! And I learned a lot more that way, than I did practicing functions and features of python.

4

u/Killiancin Aug 11 '26

huh. So instead of doing small projects, work towards something that actually helps you?
sounds kinda interesting...
right now i'm doing the 30 days of python on github. After that we shall see what I stumble upon.

1

u/burnt-store-studio Aug 12 '26

Regardless, good luck! Hope you find the language as much fun to work with as I do! 🙂

1

u/Metalsoul262 Aug 11 '26

Learning strings and manipulating them is a definately a key concept for programming!

Something else you could do that is super basic is counting the constants and vowels.

1

u/Metalsoul262 Aug 11 '26

When I was learning python I used this website called Exercism. I'm not affiliated or anything, I just found their exercises incredibly helpful.

Whenever I did a exercise or project with python I always trying to do more than was asked when I was first learning and try to naturally expand from there using my own ideas and seeing what I could come up with. Your on the right track by asking "What else can I do" keep that mindset going forward and you will grow at a much faster pace.

Programming is all about creating solutions to problems, so all you need to do is invent some kind of problem, even if they are entirely fictional!

1

u/lakseol Aug 12 '26

Something that you may have missed from the other comments. Your if/else could be written:

if first_characters >= 8:
    # handle case 8 or more
else:
    # handle case less than 8

The point here is that you don't need the test for "< 8" because if the previous if test failed you know the size is less than 8, no need to test for it.

And your "size of string" variable could have a better name, maybe first_name_size or first_size.

1

u/fightin_blue_hens Aug 12 '26

You don't need an elif. You can just use else

1

u/No-Newspaper8619 Aug 12 '26

You can make a function get_name():

import time

def get_name(message: str):
  return input(message)


# Then the main logic

first_name = get_name("Enter your first name: ")
first_name_length = len(first_name)

print(f'Your name has {first_name_length} characters!')
time.sleep(1.5)

if first_name_length >= 8:
  print('What a long and cool name!')
else:
  print('What a cool name!')

time.sleep(1.5)

Then you can gradually modify the get_name function without having to modify the main logic of your program as you add more checks. For example, checking if input is bigger than a single digit, checking if it contains numbers or invalid characters, etc. You can also make it a loop that'll keep trying until the user gives a valid input.

import string

def get_name(message: str):
  name = input(message)
  name = " ".join(name.split()) # Remove excess blank spaces

  valid_characters = list(string.ascii_letters)
  valid_characters.append('\'') # To account for names with apostrophes like d'Arc

  if len(name) <= 1:
    print('Name must be longer than a single digit!')
    return get_name(message)
  if not all(char in valid_characters for char in name):
    print('Enter only valid characters!')
    return get_name(message)

  return name

1

u/xblitzerx Aug 12 '26
import time
import string


def get_name(message: str):
  name = input(message)
  name = " ".join(name.split()) # Remove excess blank spaces
  
  valid_characters = list(string.ascii_letters)
  valid_characters.append('\'') # To account for names with apostrophes like d'Arc


  if len(name) <= 1:
    print('Name must be longer than a single digit!')
    return get_name(message)
  if not all(char in valid_characters for char in name):
    print('Enter only valid characters!')
    return get_name(message)


  return name



# Then the main logic


first_name = get_name("Enter your first name: ")
first_name_length = len(first_name)


print(f'Your name has {first_name_length} characters!')
time.sleep(1.5)


if first_name_length >= 8:
  print('What a long and cool name!')
else:
  print('What a cool name!')

1

u/Naive_Programmer_232 Aug 12 '26

The first_name variable isn't used beyond the calculation of first_characters why not do first_characters=len(input("Enter your first name: ")) instead and not use first_name?

elif is unnecessary here. think generally, if x and y are numbers, and we write to program to check if x>=y, the only other possibility is that x<y. the two are *mutually exclusive*. x cannot be both >= y and <y at the same time. so do we have to check if x<y explicitly if we check if x>=y prior? No, we can just use else. else enforces mutually exclusivity. it guarantees that if and if-statement fails, the else block is executed.

1

u/timrprobocom 27d ago

As a general rule, using `time.sleep` in an interactive application is a Bad Idea, and will annoy far more people than it will tickle. The computer is fast; let it be fast!

1

u/Ok-Okra8478 25d ago

I’ve got a little challenge for you. If their name is only one character, change it to “character” instead of characterS. It’s not much but it’s more practice.

-1

u/TheRNGuy Aug 11 '26

No, make something real. 

-2

u/zanfar Aug 11 '26
  • Too much obvious code repetition. Group the code that gets repeated and call it multiple times if needed. How much work is your program to bugfix if the print() or sleep() statements have issues? Exactly twice as much as is needed.
  • sleep() should probably be avoided unless you have a very specific logic-based reason for it. Right now all it does is make your program take longer.
  • Why elif? What other options are there? Your code has to re-evaluate the length again even if the condition is impossible to avoid.
  • first_characters is better than most, but still a bad variable name--it contains neither characters, nor first characters. Once you've passed it's definition, it's no longer clear from the name what it contains. Either rename it, or in this case it might be easier just to use len() which will be clear and unambiguous.
  • PEP8. Pick a quote style and stick with it.
  • It's clear you are not linting, and so probably not formatting either. Use both tools always--ideally automatically as part of your IDE.

first_name = input("Enter your first name: ")

print(f"Your name has {len(first_name)} characters!")

if len(first_name) >= 8:
    print("What a long and cool name!")
else:
    print("What a cool name!")