[CS50] 07 Python

8 minute read

Published:

In this post, the seventh lecture of CS50 is summarized.

Compile vs Interpreter

To run C code, we have to run clang, the C language compiler and obtain machine code.

clang -o hello hello.c -lcs50
./hello

But in Python, we’re going to get rid of this step and quite simply run it as follows.

python hello.py

Now our files ending with .py, which is an indication to the OS, that this is a python program. But unlike C, wherein we’ve been in the habit of compiling our code and running it, with Python those 2 steps get reduced into one. You don’t explicitly compile it anymore. You instead just run a program called python, similar in spirit to clang. But whereas clang is a compiler, python will see as not only the name of the language, but th ename of a program. And the type of that program is that of interpreter. An interpreter is a program that reads our code and does what it says without having the intermediate step of first having to compile it in 0’s and 1’s.

Why we use python

Remember how we write code in C to make blur filter? In python, we simply do the same thing as below.

from PIL import Image, imageFilter

before = Image.open("bridge.bmp")
after = before.filter(ImageFilter.BoxBlur(10))
after.save("out.bmp")

Why C or why python? Python is slower and takes more memory than C. It’s because Python itself is managing memory for you. And it doesn’t necessarily know a priori how much memory you’re going to need. Python’s got to maybe do its best effor for you and try to manage memory for you, and there’s going to be some overhead. The fact that I have fewer lines of codes means that python includes written lines of code to give me such functionality. So it might take me a bit more time but think about how much time it has saved in terms of writing the code more quickly and readable. By C, we can understand what’s going on underneath the hood, but with Python we can express the solutions to problems all the more efficiently, all the more readily. Since python have very rich ecosystem of libraries that other people wrote, you can literally run a command like pip to install and use fancy tools.

libraries

To use libraries in python, you can use import.

import cs50

Or you can be more precise by writing specific functions.

from cs50 import get_string

answer = get_string("what's your name? ")
print(f"hello, {answer}")

function define order

As mentioned in https://arcstone09.github.io/study/2024-03-31-cs50-2, a function should be defined or its prototype should be declared before it is called. Thus the code below gives you an error.

void a(void){
    b(); //call function b
}

void b(void){
    printf("test\n");
}

int main(void){
    a(); // call function a
}

It is because function b is defined after it is called in function a. The solution is you can either change the order of the definitions of function a and b or add function declaration.

// solution 1
void b(void){
    printf("test\n");
}

void a(void){
    b(); //call function b
}

int main(void){
    a(); // call function a
}
// solution 2
void a(void);
void b(void);

int main(void){
    a(); // call function a
}

void a(void){
    b(); //call function b
}

void b(void){
    printf("test\n");
}

In Python, a function should be defined before it is called. The code below will occer NameError.

a()

def a():
  print("test")

I could simply flip the order, but when we have many functions it’s probably naive to assume I can just keep putting my functions above because that’s going to move my main code - in this case, a() - to the bottom of the file. So it turns out in Python, even though you don’t need a main() function, it’s actually quite common to define one nontheless.

def main():
  a()

def a():
  print("test")

main()

In the code, function a() is called inside function main(). By the time main() is called in last line, function a() has already been defined. So, there’s no error because a() is defined beforeo it’s called. Howver, in C, the order of function declarations matters. When the compiler encounters a function call, it needs to have seen a declaration or definition of htat function earlier in the code. This is different from Python. In our earlier C code where functions are defined in the order a-b-main, when the compiler sees the call to b() inside a(), it doesn’t know what b() is because it hasn’t seen it yet.

In short, in Python, a function must be defined before it is called in the actual execution flow. In C, a function must be defined or at least declared before the line where the function call is written.

Truncation

x = 1
y = 3
z = x / y
print(z)

In C, truncation would happen and it will print out 0.00000. In python, it prints 0.333333. So python is a little smarter when it comes to converting one value to another.

Floating-point imprecision

x = 1
y = 3
z = x / y
print(f"{z:.50f}")

It will print out 0.33333333148296… which is not exact value. So floating-point imprecision problem still exists in python.

Integer overflow

In python, integer overflow does not exist. When you have an integer, python will reserve more and more memory for the integer as it grows. It is not a fixed number of bits.

Exceptions

In C, the only way we could handle errors is by having functions return special values. For instance, malloc() could return NULL, which means it ran out of memory. We could write our own functinos that return values to indicate something went wrong. But the problem in C is that if you’re stealing certain values for errors, your function can never return that values as actual values because other people are going to interpret them as errors. In Python, you can instead have more out of band error handling known as exceptions.

$ python test.py
Traceback (most recent call last):
  File "/test.py", line 12, in <module>
    main()
    ...
ValueError: invalid literal for int() with base 10: 'cat'

You might have seen this kinds of text in your terminal while executing python script. This is an exception. In this case, the type of exception happens to be called a ValueError. There is a way to handle this.

def get_int(prompt):
  while True:
    try:
      return int(input(prompt))
    except ValueError:
      print("Not an integer")

for-else clause

names = ["Carter", "John", "David"]

name = input("Name: ")

for n in names:
  if name == n:
    print("Found")
    break
else:
  print("Not found")

In Python, if you break out of a loop, that’s it for the for loop. If though, you get all the way through the list that you’re looping over, and you never break, else clause will be runned.

sys

There are other libraries that come with Python, not even third-party, and one of them is the sys library, whereby you have system-related functionality. What this means is that certain functionality that was just immediately available in Cis sometimes tucked away now into libraries in python. If you want to do command-line arguments in python you can do as below.

from sys import argv

if len(argv) == 2:
  print(f"hello, {argv[1]}")
else:
  print("hello, world")

If you want to exit out of the program entirely you can do as below.

import sys

if len(argv) != 2:
  print("Missing command-line argument")
  sys.exit(1)

print(f"hello, {argv[1]}")
sys.exit(0) 

Just like in C, if you want to exit from a program with 1 or 2 or anything else, you can use sys.exit.

pip

pip command allows me to install more functionality from a third party into my programming environment.

$ pip install qrcode

qrcode library generates QR codes automatically.

import qrcode

img = qrcode.make("https://youtu.be/svFZjo5PgG0")
img.save("qr.png", "PNG")

Inside of this img varialbe, which is a different data type that this library gave me, doesn’t come with Python, I can save a file like qr.png and save it in the PNG format, the Portable Graphic Network Graphic.

Leave a Comment