Post Reply 
Python issue with implicit data types
08-01-2024, 11:08 AM
Post: #1
Python issue with implicit data types
I'm currently experiencing Python on a HP Prime and I converted a HPPL Mandelbrot program to python (HPPL wrapper). Python does not seem to declare variables with an explicit data type. It seems just to assume a proper type and it seems to convert from type to type if necessary. I took me hours to get into the following issue:

The Mandelbrot program calculates three colors R, G, B using math functions like sin(). So, the result is a float variable in the range of zero to 255. I want to draw a point with the calculated color and want to pass it to the pixon() function. So, I need a 24-bit color value which I thought I can calculate as
col = (R*256 + G)*256 + B

I used this value with pixon() but the colors of the Mandelbrot picture are messed up then. pixon() doesn't seem to handle a float color variable correctly although the value itself is the correct color value. I changed the color calculation to:
col = (int(R)*256 + int(G))*256 + int(B)
and the picture is drawn with correct colors.

My first question: Is it true that pixon() and probably other python drawing functions make a difference whether the color parameter is float or integer? Is this probably a bug?

The other question I have is, how can I handle implicit and probably unwanted type conversions in python.
Find all posts by this user
Quote this message in a reply
08-01-2024, 08:13 PM (This post was last modified: 08-01-2024 08:25 PM by nbc12.)
Post: #2
RE: Python issue with implicit data types
I can't comment on the behavior of pixon, but I do know that Python isn't designed to be strongly typed. I don't have much experience with Micropython or Python on the Prime, but I have been using Python for over 10 years, and currently write Python for work.

I don't know your programming background or level of experience with Python, but you can mitigate unintended behavior of weak typing with a few tools:

To convert between types, you can simply wrap the type in the "constructor" of the desired type. str(5) returns '5', int(5.5) returns 5, etc.

Usually the only type conversions I need for numeric programs (mandelbrot etc) are:
  • str -> int: int(). Note that int() has a second position parameter for specifying the base of a string, which defaults to 10.
  • str -> float: float().
  • int -> str/float -> str: int to str conversion is usually implicit for me because I use Python's f-string formatting, which I would recommend using. In the event that you don't want to create an entire formatted string, you can just use str().
  • float -> int: math.ceil(), math.floor(), round(), and int(). Note that int() truncates, which is different from flooring for x < 0.
  • int -> float: I almost never wrap ints with float() in my code unless it increases readability for my future self. Besides readability, there is no reason to doing so because Python will automatically return a float if an operation requires it. For example, 5 / 4 returns a float. To perform integer division, use two slashes like this: 5 // 4.

Also, if at least one operand of a math operation is a float, the output will always be a float even if the value can be represented by an integer, excluding % and // for obvious reasons.
For this reason, some of your variables will probably be a float even if they are representing an int. This can be frustrating for low level folks, myself included, but it's just an attribute of Python I've had to get used to. It doesn't usually impact anything anyway.

I usually don't need to worry about making a distinction between floats and ints. I just floor/ceil/round/truncate everything as needed for program logic. Just make sure to convert everything at the end of your calculations if you are passing it to an external library function that takes an int, obviously.

You can also use isinstance() combined with an if statement to change the program flow depending on a type at runtime.

Code:
x = isinstance(y, int)

where x is a bool that is true if y is an int. Note: This does not see 4.0 as an integer. A numeric type is only a float if it has a decimal. Otherwise, it's an int. You can use int(x) == x if you want to check if the fractional part is zero.

For debugging types, you can use
Code:
print(type(x))
to see what the type of a variable is at runtime.

Hope this helps!
Find all posts by this user
Quote this message in a reply
08-01-2024, 09:23 PM
Post: #3
RE: Python issue with implicit data types
(08-01-2024 11:08 AM)34C Wrote:  My first question: Is it true that pixon() and probably other python drawing functions make a difference whether the color parameter is float or integer? Is this probably a bug?

MicroPython on other calculators, such as the TI and Numworks, have no problem with fractional coordinates in graphics statements so it is a limitation unique to the Prime.

Tom L
Cui bono?
Find all posts by this user
Quote this message in a reply
08-01-2024, 09:33 PM (This post was last modified: 08-01-2024 09:37 PM by bxparks.)
Post: #4
RE: Python issue with implicit data types
Lots of good advice, but allow me to nitpick the following:

(08-01-2024 08:13 PM)nbc12 Wrote:  Python isn't designed to be strongly typed

Python is generally considered to be a strongly but *dynamically* typed language. (See for example, this Stack Overflow article for a much longer discussion about weak/strong versus static/dynamic typing.)

In practice, this means that the type in Python is bound to the *value* not the variable. A variable, for example 'col', can be assigned to hold a float, an int, or a string, all within the same function. If you try to apply a string operation on 'col' while it is holding a float, then Python will throw a runtime exception.

I post this because other things on the internet about Python may be confusing without understanding this distinction.
Find all posts by this user
Quote this message in a reply
08-02-2024, 04:13 PM (This post was last modified: 08-02-2024 04:15 PM by Albert Chan.)
Post: #5
RE: Python issue with implicit data types
Hi, 34C

col = (R*256 + G)*256 + B

Formula is to pack color fields into 1 number, with R,G,B as integers, 0 to 255
If variables have fractional parts, it will mess up the combined packed color value.

Your fix is really the correct formula, may not be Python type issue at all.

col = (int(R)*256 + int(G))*256 + int(B)

To confirm, add 1 more statement, and see if colors changed

col = float(col)
Find all posts by this user
Quote this message in a reply
08-03-2024, 09:25 AM
Post: #6
RE: Python issue with implicit data types
(08-02-2024 04:13 PM)Albert Chan Wrote:  Your fix is really the correct formula, may not be Python type issue at all.

Thank you for all the helpful information. I have little experience with Python so far and now I have a better understanding of how Python deals with data types. I understand that in this case it was actually necessary to first convert the RGB parts from float to int in order to cut off the decimal places.
Find all posts by this user
Quote this message in a reply
Post Reply 




User(s) browsing this thread: 3 Guest(s)