Python for PHP Developers: Deep Dive Part 2


What is it like moving from PHP to Python? Part 2 explores Python’s float, string, and list operators and operations.

Using the broad overview from learningpython.org, we’ll examine the ins and outs of Python from a PHP developer’s perspective, while showing the equivalent PHP and Python code side-by-side.

Clone github.com/bill-c-martin/python-for-php-devs to get a Python environment setup and to follow along with the code examples in this series.

In Part 2 of this series, we will examine these in more detail to see how they compare in Python vs PHP:

Table of Contents

Numbers

Like PHP, Python is dynamically-typed. Therefore, numbers and arithmetic in Python more or less behave how they do in PHP, with a few key differences.

Floats

Displaying floats in Python works better, since it doesn’t require a special function to regain lost .0’s like PHP.

PHP

$x = 2;
echo $x;

// php is terrible for this
$y = 3.0;
var_dump( number_format((float)$x, 1, '.', '') );

// even when typecasting to float, you still need number_format()
$x = (float) 4;
var_dump( number_format($x, 1, '.', '') );

Python

Simplicity.

x = 2
print(x)

y=3.0
print(x) # prints 3.0

z=float(4)
print(z) # prints 4.0

Arithmetic

Arithmetic in Python is mostly what you’d expect, coming from PHP.

+, -, *, /, and % all do exactly what you’d think they’d do for numeric arithmetic.

And for non-numeric types, as covered in Part 1 (magic methods), they behave differently.

However, there are a couple Python arithmetic operators not found in PHP:

PHP does of course have this functionality through its pow() and floor() methods. And to be fair, those ** and // “operators” in Python are just syntax sugar for magic methods anyways.

But they are still worth calling out, because to PHP eyes, ** looks like a syntax error, and // looks like a comment!

PHP

# 5^3 power
echo pow(5,3); // prints: 125

# Floor division:
echo floor(9 / 2);     // prints: 4
echo floor(9.0 / 2.0); // prints: 4
echo floor(-11 / 3);   // prints: -4
echo floor(-11.0 / 3); // prints: -4

Python

# 5^3 power
print(5 ** 3) # prints: 125

# Floor division:
print(9 // 2)     # prints: 4
print(9.0 // 2.0) # prints: 4.0
print(-11 // 3)   # prints: -4
print(-11.0 // 3) # prints: -4.0

One other interesting thing about floor division worth calling out for Python is that last example, above. Notice that floor division involving one or more floats will result in a float being returned, even though floor division, by definition, results in a whole number.

On the topic of automatic type conversion, it’s also worth noting that like PHP’s Type Juggling feature, Python also performs automatic type conversion depending on the context.

For example, dividing an int by a float produces a float in both:

PHP

$x = 1 + 2 * 3 / 4.0;
var_dump($x); // prints: 2.5

Python

x = 1 + 2 * 3 / 4.0
print(x) # prints: 2.5

Strings

Concatenation

String concatenation in Python resembles JavaScript, which is similar enough to PHP.

PHP

echo 'hello' . ' ' . 'world';

Python

print('hello' + ' ' + 'world')

Remember from Part 1: + is just the __add__ magic method that all strings have, which in the case of strings, performs concatenation.

Repetition

String repetition in Python is an interesting Ruby-esque quirk.

To repeat a string, you multiply it by an integer. For example: 'Ho ' * 3.

PHP

str_repeat('Repeat', 3); // prints: RepeatRepeatRepeat

Python

print('Repeat' * 3) # prints: RepeatRepeatRepeat

Same as +, this * operator is just the __mul__ method that all strings have, which returns a repeated string n times. As in: 'Repeat.__mul__(3).

Substitution

String substition will feel familiar, with some key differences.

With PHP:

With Python, everything can just go through print().

Except when it doesn’t. There’s actually 3 different ways.

Let’s start with the % way:

Python

# single substitution
name = 'john'
print('Hello, %s' % name)

# 2 or more substitutions
first = 'john'
last = 'smith'
print('Hello, %s %s' % (first, last))

It must surely seem strange to see that % operator preceding the tuple of variables like that, which is inherently confusing since % is supposed to do.. modulo things.

But like + and *, % is just syntactic sugar for __mod__. So what is really happening here is 'Hello, %s %s'.__mod__( (first, last) ).

Why is the string interpolation operator the modulo operator? Nobody knows.

And what about that (first, last) part, and its “redundant” parenthesis? Remember, that is a tuple: a collection of constants basically. It’s kind of like passing an array into a function in PHP. If you lose the parenthesis, you would be passing two strings, instead of a single tuple collection of strings.

You can also do some elegantly useful formatting things inside strings with %s, %d, and %f:

Python

one = 1
two = 2.0
three = 'three'

# prints: Counting: 1, 2.000000, three
print("Counting: %d, %f, %s" % (one, two, three))

# Rounding. Prints: More: 1.15656566, Less: 1.1566, Even less: 1.2
y = 1.15656565656
print("More: %.8f, Less: %.4f, Even less: %.1f" % (y,y,y))

# Lower/uppercase. Prints: Int: 14, lowercase x: e, uppercase x: E
x = 14
print('Int: %d, lowercase x: %x, uppercase x: %X' % (x,x,x))

There’s also str.format(), which is overly verbose, and rather unintuitive how one can’t just pass the variables into the function as format(first, last, age):

Python

first = "John"
last = "Smith"
age = 22

print("Hello, {first} {last}, who is {age} years old.".format(first=first, last=last, age=age) )

And finally, there are f-strings: the newest way to accomplish string interpolation.

Python

first = "John"
last = "Smith"
age = 22

print(f'Hello, {first} {last}, who is {age} years old.')

Note that f hugging the front of the string.

Also, there’s supposed to be a joke that goes:

Do you love strings in Python?

f’Yes!’

Operations

In Python, since strings are objects, they contain a whole pile of methods useful for doing operations, not to mention all those __special_methods__ discussed previously.

As a PHP developer, chaining these string methods off of strings would feel familiar if you’ve written TypeScript before.

Python strings have two types of string operation syntax:

This is a departure from PHP, where string processing is always done through standalone functions available in the language itself, like strpos(), explode(), strtoupper(), and substr().

Let’s start with Python string operations that use that method syntax, and compare them to PHP.

Python

x = 'Hello world'

# length
print(len(x))            # prints: 11

# character position
print(x.index('o'))      # prints: 4

# counting occurrences
print(x.count('l'))      # prints: 3

# transforming
print(x.upper())         # prints: hello world
print(x.lower())         # prints: HELLO WORLD

# splitting
print(x.split(" "))      # Prints: ['Hello', 'world']
print(len(x.split(" "))) # Prints: 2

PHP

$x = 'Hello world';

// length
echo strlen($x);              // prints: 11

// character position
echo strpos($x, 'o');         // prints: 4

// counting occurrences
echo substr_count($x, 'l');   // prints: 3

// transforming
echo strtoupper($x);          // prints: hello world
echo strtolower($x);          // prints: HELLO WORLD

// splitting
print_r(explode(' ', $x));    // Prints: ['Hello', 'world']
echo count(explode(' ', $x)); // Prints: 2

Pretty similar, with Python being more elegant and consistent in naming, which is nothing suprising, because PHP.

Now, let’s look the Python string operations tha use that array/List syntax, and compare them to PHP.

Python

x = 'Hello world'

# string slicing
print(x[3:7]) # prints: lo w

# single character capturing
print(x[3]) # prints: l

# slicing to end-of-string
print(x[3:]) # prints: lo world

# slicing from beginning-of-string
print(x[:7]) # prints: Hello w

# slicing last n characters
print(x[-3:]) # prints: rld

PHP

$x = 'Hello world';

// string slicing
echo substr($x, 3, 4);   // prints: lo w

// single character capturing
echo substr($x, 3, 1);   // prints: l

// slicing to end-of-string
echo substr($x, 3);      // prints: lo world

// slicing from beginning-of-string
echo substr($x, 0, 7);   // prints: Hello w

// slicing last n characters
echo substr($x, -3, 3);  // prints: rld

Again, pretty similar. Just syntac sugar really.

Now let’s look at some string operations where Python and PHP can be wildly different.

Up first is starts/ends with, which PHP did not have a native equivalent until PHP 8:

Python

x = 'Hello world'

print(x.startswith('Hello')) # prints: True
print(x.endswith('rld'))     # prints: True

PHP

$x = 'Hello world';

// Before PHP 8..
echo substr($x, 0, strlen('Hello')) === 'Hello'); // prints: true
echo substr($x, -strlen('rld')) === 'rld');       // prints: true

// After PHP 8..
echo str_starts_with($x, 'Hello');                // prints: true
echo str_ends_with($x, 'rld');                    // prints: true

It suprisingly has taken PHP until 2020 to have something non-tedious for that!

Up second is string stepping, which is certainly a Python string operation I have never seen in PHP before:

Python

x = 'Hello world'

# slicing while stepping n characters
print(x[1:7:2]) # prints: el

# string reversing, using stepping
print(x[::-1]) # prints; dlrow olleH

Of course, PHP has strrev() for string reversing though.

So what is string stepping in Python? It’s that 3rd “parameter” and is a like an interval or iterator.

[1:7] is slicing out the 2nd to 8th characters from the string, but [1:7:2] is doing the same, except skip every other character while doing that.

[:] is basically request every character from the beginning until the end of the string, but [::-1] is doing the same, except go backwards for each character returned.

So the equivalents in PHP would be a mess of strlen(), explode for array conversion, for loops for iterating, and iterators like $i+2 to mimic the stepping.

The take away here is that although PHP and Python have a lot of similarity in string operations, it’s really Python’s terse syntax and slicing flexibility that are a win, and lends itself well to the machine learning community slicing and dicing up data to train algorithms.

Lists

PHP numeric arrays are called Lists in Python, and the two are quite similar, with some key differences.

Appending and Looping

However, pushing elements and looping feels more like Javascript:

PHP

// Farewell to our beloved push syntax
$mylist = [];
$mylist[] = 1;
$mylist[] = 'two';
$mylist[] = 3.0;

// Array looping
foreach($mylist as $x) {
    echo $x;
}

Python

# append() adds new elements
mylist = []
mylist.append(1)
mylist.append('two')
mylist.append(3.0)

# Array looping
for x in mylist:
    print(x)

Initialization

Like PHP, you can declare and initialize a List all in one go. The syntax is the same:

PHP

$that_list = [1,2,3,4];
foreach($that_list as $x) {
    echo $x;
}

Python

that_list = [1,2,3,4]
for x in that_list:
    print(x)

Out of Bounds Elements

Accessing non-existent elements earns you an exception in Python, instead of PHP’s warnings:

PHP

$mylist = [1,2,3,4];
echo $mylist[6]; // causes a warning, but the show goes on.

Python

mylist = [1,2,3,4]
try:
    print(mylist[6])
except:
    print('good thing I caught this exception')

Repetition

That repeating * “operator” from earlier is back already. It works for Lists too.

Which means List objects have their own defined __mul__ method like strings do.

PHP

Note how there is no elegant way to do this in PHP with arrays, not even an ArrayObject:

$source_list = [1,2,3];
$new_list = [];

for($i=1; $i<=10; $i++) {
    $new_list = array_merge($source_list, $new_list);
}

print_r($new_list);

Python

But in Python: Simplicity.

print([1,2,3] * 10)

Concatenation

Moving along with the List arithmetic theme, that intuitive * way of working with Lists in Python applies with the + operator as well:

PHP

$even = [2,4,6,8];
$odd = [1,3,5,7];
print_r( array_merge($even, $odd) ); // prints [2,4,6,8,1,3,5,7]

Python

Simplicity.

even = [2,4,6,8]
odd = [1,3,5,7]
print(even + odd) # prints [2,4,6,8,1,3,5,7]

+ is syntactic sugar for List.__add__ in this case.

Multiple Variable Assignments

Assignments are mostly what you’d expect, but there are some interesting differences between PHP vs Python to call out here with multiple variable assignments.

Multiple Variable Assignments to Same Value

Initializing a bunch of variables to a single value is what you would expect:

PHP

$a = $b = $c = 1;
var_dump($a, $b, $c); // prints: 1 1 1

Python

a = b = c = 1
print(a, b, c) # prints: 1 1 1

However, there is a curveball when doing this with Lists in Python.

Consider the below 3 variables assigned to the array. As we know, PHP copies the array into each assignment. So you are free to modify one variables without impacting the others.

Not so with Python. Python “points” all 3 variables to the same array in memory. Meaning, when the array changes, all 3 variables change with it.

PHP

$a = $b = $c = [1];
$b[] = 2;
var_dump($a, $b, $c); // prints: [1] [1,2] [1]

Python

a = b = c = [1]
b.append(2)
print(a, b, c) # prints: [1,2] [1,2] [1,2]

Multiple Variable Assignments to Multiple Values

This one is worth noting since I’ve rarely seen this in PHP, but frequently in Python.

PHP

Historically, we usually used list() to capture multiple return variables from a function into multiple variables:

function some_function(){ return [1, 2, 3]; };
list($a, $b, $c) = some_function();

There’s also square bracket syntactic sugar available since PHP7. Both can be used to also just assign multiple variables on a one-liner:

list($x, $y, $z) = [1, 2, 3];
var_dump($x, $y, $z); // prints: 1 2 3

[$x, $y, $z] = [1, 2, 3];
var_dump($x, $y, $z); // prints: 1 2 3

Python

However, Python loses all the syntactic fluff and just has comma-separation and that’s it:

a, b, c = 1, 2, 3
print(a, b, c)  # prints: 1 2 3

Conclusion

In Part 3, we will get into Python loops, conditions, functions, and classes, while comparing it to PHP-equivalent code every step of the way.