Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Python

My Questions to Python

4.70/5 (5 votes)
27 Oct 2023CPOL3 min read 8K  
Python became a quite popular programming/scripting language recently. But, after some inspiring experience, I've got some open questions...
I'm quite old to know that there are other languages more suitable for scripting, but I was asked to use more fancy (and less efficient) programming languages for scripting, because the new generation of developers doesn't even know about Perl and Shell scripting languages. I have to use Python to earn money and I'm not happy with this.

Introduction

Python is not a brand new programming language. It has got quite a long history of development. But it has still has got some unexplainable issues and I will try to reveal them within the article below.

Background

I was asked to use Python instead of Perl recently. I understand that Perl is still strong enough, but its development is a bit frozen. And it is strategically wise to switch to other languages with more active development to avoid dead end way. So, I don't really hate the modern programming languages, but I have to notice some issues that are making support process of the software created with these languages more difficult and exciting.

Using the Code

A code in the article contains the examples of the things that you must not do. Please don't use it at work and, of course, at home. Please avoid these example code patterns in the working code. The code has been written and "tested" with Python 3.11.

What Can You Catch From Python Code

Obvious Coding Issues

Here is an example of the text processing Python class:

Python
import sys
import platform
from io import TextIOWrapper

class FileReader:

    def __init__(self, inFileName: str, outFileName: str):
        plName = platform.system()
        if plName == 'Windows':
            self.isWindows = True
            self.newline = "\r\n"
        else:
            self.isWindows = False
            self.newline = "\n"
        if len(inFileName) < 1:
            self.stdin = TextIOWrapper(sys.stdin.buffer,
                                       newline="",
                                       encoding="utf-8")
        else:
            self.stdin = open(inFileName, "r", 1, encoding="utf-8")
        if len(outFileName) < 1:
            self.stdout = TextIOWrapper(sys.stdout.buffer,
                                        newline=self.newline,
                                        encoding="utf-8")
        else:
            self.stdout = open(outFileName, "w", 1, encoding="utf-8")
        self.someData = ''

    def getData(self) -> str:
        return self.someData

    def decodeSomeThing(self, txt: str, al1: list) -> str:
        atx = txt.split(',')
        al1[1] = '3'  # you will modify the value here and everywhere
        txt = atx[0]  # you will modify the local value here, but not outside
        return txt


fr = FileReader('','')
as1 = ['1','2']
s1 = 'some, things'
s2 = fr.decodeSomeThing(s1,as1)
print(s1,s2, as1)
print(fr.getData)

Please take a look at the last row of the code example above. I expected an error output like:

Terminal
AttributeError: 'FileReader' object has no attribute 'getData'

But there is not:

Terminal
some, things some ['1', '3']
<bound method FileReader.getData of <__main__.FileReader object at 0x7f950a5befd0>>

It is connected to the other language features, but it makes development and support process more exciting. :-)

Most of the things in Python will be passed by reference, but some are not. And you must learn it to make your code more predictable. Take a look at the rows with comments. Value of the s1 remains unchanged outside the function decodeSomeThing(), but the value of the as1 will be modified (see terminal example above).

Integer rounding "issue"

I was not expecting to see the integer rounding error issue below, but I saw it:

Python
#!/usr/bin/env python3
import sys


class MultiNumber:
    CHARSET64 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz, '
    CHARSET36 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

    def __init__(self, charz: str = CHARSET64):
        self.charz = charz
        self.ord = len(self.charz)

    def encode(self, num: int) -> str:
        s1 = ''
        n1 = num
        while n1 > 0:
            n2 = int(n1 % self.ord)
            s1 = self.charz[n2] + s1
            n1 = int(n1 / self.ord)
        return s1

    def decode(self, snum: str) -> int:
        mul = 1
        n1 = 0
        i = len(snum) - 1
        while i >= 0:
            s1 = snum[i]
            ni = self.charz.find(s1)
            if ni > 0:
                n1 = n1 + (ni * mul)
            else:
                if ni < 0:
                    sys.stderr.write("Unable to decode character:'{0}' at pos {1}".format(s1, i))
                    break
            mul = mul * self.ord
            i = i - 1
        return n1


def main(argv):
    mn = MultiNumber(MultiNumber.CHARSET36)
    for arg in argv:
        n = int(arg)
        s1 = mn.encode(n)
        n1 = mn.decode(s1)
        print('{0:X} -> "{1}" -> {2}'.format(n, s1, n1))


if __name__ == "__main__":
    main(sys.argv[1:])

When I run the code above, I will receive the output:

Terminal
-bash $ ./multinumber.py 9223372036854775807
7FFFFFFFFFFFFFFF -> "1Y2P0IJ32E807" -> 9223372036854775303

The encoding result is not valid (proper result must be "1Y2P0IJ32E8E7"). And when I run the C implementation of the encoding:

C++
char* encode(int64_t n1, const char* charz)
{
    int64_t n2;
    static char s1[12];
    int64_t ord = strlen(charz);
    char* ptr = (s1 + sizeof(s1) - 1);
    char chr;
    *ptr = '\0';
    while (n1 > 0)  {
        n2 = n1 % ord;
        chr = charz[(size_t)n2];
        ptr --;
        *ptr = chr;
        n1 /= ord;
    }
    return ptr;
}
...
char* s1 = encode(9223372036854775807, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");

I receive a proper result.

Integer rounding "issue" explanation

As it was highlighted by Matthew Barnett in comments, my mistake was in syntax. That's not a rounding error as I thought. As from my previous experience with the other languages, mathematical operations are performed after all the operands are converted to the same type. And I was sure that Python does an implicit conversion to the result type for all the operands. But for integer division there is another operator (//) that I haven't noticed about. Well, I need to learn this lesson and my study for Python is far away from its end. Nobody is perfect, even if someone thinks so.

Points of Interest

I did not see anything exceptional with the issues highlighted in the article above. They are usual consequence of the programming languages development. I hope they will be fixed in the next releases. Or such a things have just highlighted more prominent in the documentation.

History

  • 25th October, 2023: First edition
  • 25th October, 2023: Second edition (some issue fixed)
  • 27th October, 2023: Logical mistake highlighted and explained (I hope so)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)