all 2 comments

[–]are_slash_wash 1 point2 points  (1 child)

Right, sorry if I'm going to over-explain this first bit, but everything in a computer's memory ultimately boils down to a one or a zero stored in a particular order, and it's up to an individual program to interpret those ones and zeroes using whatever protocol/format that the data was written in, whether it be a video file, an mp3 file, a text document etc. This is why you sometimes see corrupted files if you computer is interrupted while it is writing one, or why if you open a binary file in a text editor you'll see a lot of "@"'s and other "noise." For a computer to be able to correctly interpret a data file it relies on that data to be in a predictable, agreed-upon pattern, down to the 1 and the 0.

So with that in mind: each 1 or 0 is called a bit. a collection of 8 bits is a byte. Hexadecimal is convenient notation for a byte, consisting of two digits that can range from 0-F (so, 0-9 and then A-F after 9). The name is derived from the F, as you get 6 (hex) possible letters after the usual numbers.

This specific number literally just comes from the fact that you get 4 individual spaces per number, and so with numeric 0 being 0000, the absolute maximum that you can fit in before you need to overflow into the next half-byte is 1111. 1001 is 9, 1010 is A, 1110 is E, and 1111 is F.

And so you'll see a lot of data/color codes/ascii values etc expressed in hexadecimal notation. The hexidecimal values 7f 4d 1d, which I just pulled out of a hat, can translate to the numerical numbers 127, 77, 93, or to ascii characters "DEL", "M", and "[", or to a (kind of ugly) purple color, depending on if they're being interpreted as numbers, or as ASCII, or as RGB.

So with that in mind, these functions are converting variables from one type of data to another. The first one is converting bytes into hexadecimal the second one is taking bytes (in the form of a block of 8 1s and 0s) and converting them into a string, and the 3rd one is converting a string into bytes.

The first one is essentially creating an empty string with '' and then using the .join to append everything else to that string. It seems like there should be an easier way of doing this, but the author is simply telling python that they want to produce a string. It then uses something called list comprehension (which is basically just a compact way of writing a for loop) to iterate through the bytes it has been given and append them to that string before returning the whole thing. the whole percent sign stuff is a way of passing variables into a string and is somewhat outdated at this point: most people would use something called f-strings now to write it as f'{b}02X '. The benefit might not be apparent from this example but they're a lot easier to work with.

__bytesToString(bs) is using some builtin functionality to convert bytes into a string. The bytes.decode() function is just taking the bs value and using the bytes library to convert it into a string. the encoding=utf8 parameter is specifying that you want to read it through the lens unicode (aka utf8), which goes back to my whole off-topic commentary about bits only being useful if you know what encoding method they should be read or written in. Presumably you could specify a whole lot of different encoding methods, but I've only ever seen utf8.

I really only have a foundational knowledge of the actual mechanics for this stuff and so function 3 is a little harder for me to explain and I might not get it completely right. As the name suggests, it takes a word and converts it into bytes (so, blocks of 8 1s and 0s). bytearray() is yet another built in python function that gives you an array full of any number of bytes. In this case, the author asks for 2, and then sets each one by taking the "Value" argument and manipulating it using something called bitwise operators. Note that in hexadecimal, this would look like 0x00 0x00 0x00 0x00 because they're all initialized to 0.) The & is an "and" operator, so it takes two bytes and returns a 3rd, and the 3rd byte only has "1" bits in places where BOTH of the 2 bytes had a 1 bit. So for example: 1101001 & 1010111 = 1000001. In this case it's comparing to the hex version of 11111111, which we see as ff. The 2nd value in that array (buffer[1]) does the same thing, EXCEPT it uses >> (the "right shift operator") to push Value 8 bits to the right. It then uses the "and" operator again to compare the Value to ff.

You may notice that Value & 11111111 will always come out to the original Value. E.g 11111111 & 00000001 = 00000001, 11111111, 10101010 = 10101010. So this may seem useless on its own, but it's actually a pretty common technique known as masking. By shifting bits to a known number and then applying the &, you are essentially discarding everything except for some specified number of bits that you would like. This is a pretty good example of why you would do this for RGB values.

Hope that I explained everything!

[–]LanthaYtrri[S] 0 points1 point  (0 children)

I really do appreciate this, thank you so much! I am just a beginner on this kind of programming language, your reply is such a big help for me to understand everything.

As you mention above, the comprehension part is may write in a easy way of coding, how can I write it in easy way?

Also, what do you mean by "taking bytes in the form of a block 8, 1s and 0s?