Python - Arbitrary Keyword Args
#In addition to positional arbitrary args, Python also provides keyword arbitary args
>>> def cities_lived(first_name, last_name, **cities):
>>> if cities:
>>> print(f"{first_name} {last_name} has lived in {len(cities)} cities:\n")
>>> for order, city in cities.items():
>>> print(f"{order} city: {city.title()}")
>>> else:
>>> print(f"{first_name} {last_name} has not lived in any cities")
Tom Markel has lived in 3 cities:
first city: Chicago
second city: Portland
third city: Seattle
Python - Exceptions
#Python try-catch is a bit different than in other languages, and instead uses try-except
#multiple 'except' with different exception types can be defined, as well as an 'else' to execute only if no exception thrown
#last, typical 'finally' statement can be added to 'try', to execute regardless of if exception thrown or not
>>> def catch_me(numer, denom):
>>> try:
>>> int(numer)/int(denom)
>>> except ValueError:
>>> print("catch_me() call failed due to non-numerical args")
>>> except ZeroDivisionError:
>>> print("catch_me() call failed due to zero denominator")
>>> except:
>>> print("catch_me() call failed due to other exception")
>>> else:
>>> print(f"Divsion {numer} / {denom} = {numer / denom}")
>>> finally:
>>> print(f"catch_me() call finished")
>>> catch_me(12, "fish")
catch_me() call failed due to non-numerical args
catch_me() call finished
>>> catch_me(12, 0)
catch_me() call failed due to zero denominator
catch_me() call finished
>>> catch_me(12, 3)
Divsion 12 / 3 = 4.0
catch_me() call finished
#Can assign alias to exception to access various properties of exception
>>> def zero_catch(numer, denom):
>>> try:
>>> int(numer)/int(denom)
>>> except ZeroDivisionError as zero_error:
>>> print("Error: ", zero_error)
>>> print("Exception Type: ", type(zero_error))
>>> print("Exception args: ", zero_error.args)
>>> zero_catch(12, 0)
Error: division by zero
Exception Type: <class 'ZeroDivisionError'>
Exception args: ('division by zero',)
#Can manually throw specified exception with 'raise'
>>> def check_curse(name):
>>> if(name == 'Damien'):
>>> raise NameError('Cursed Name')
>>> try:
>>> check_curse('Damien')
>>> except Exception as exp:
>>> print(f'Warning: exception type {type(exp)} thrown. Exception message: {exp}.')
Warning: exception type <class 'NameError'> thrown. Exception message: Cursed Name.
PHP - Namespaces
//Namespaces provide a way to prevent name clashes across files through encapsulation
//They allow files to be grouped and together, then imported into a file, but each in their own namespace
//For example, two packages, both with User classes, could exist fine in the same including file without name clash errors occuring
//Even code without a user assigned namespace still has a namespace in PHP: the global namespaces
//Here is an example of namespaces. Assume each namespace is also part of a large package based namespace.
//NamespaceA.php
<?php
namespace SmilingStallman\DevBlog\Week24\ASpace;
class Namespacer{
public function printNamespace(){
echo "I am NamespaceA";
}
}
?>
//NamespaceB.php
<?php
namespace SmilingStallman\DevBlog\Week24\BSpace;
//same classname as class in NamespaceA.php
class Namespacer{
public function printNamespace(){
echo "I am NamespaceB";
}
}
?>
//week24-practice.php
<?php
namespace SmilingStallman\DevBlog\Week24;
include 'week-24-php/NamespaceA.php';
include 'week-24-php/NamespaceB.php';
function printNamespace(){
echo "I am Namespace Week24";
}
//unqualified name access - similar to relative filename reference
printNameSpace(); //"I am Namespace Week24"
//qualified name access - similar to relative filepath reference
$a = new ASpace\Namespacer();
$a->printNameSpace(); //"I am NamespaceA"
//fully qualified name access - similar to absolute filepath reference
$b = new \SmilingStallman\DevBlog\Week24\BSpace\Namespacer();
$b->printNameSpace(); //"I am NamespaceB"
//'use' combined with aliasing allows namespace importing while also preventing name clashes and provides shorter reference names
use \SmilingStallman\DevBlog\Week24\Aspace\Namespacer as AspaceClass;
$a_alias = new AspaceClass();
$a_alias->printNameSpace(); //"I am NamespaceA"
//Functions and consts can also be imported into a namespace using the 'function' and 'const' keywords combined with 'use'
?>
PHP - OOP General Practice
//Lets say you want to design a base Animal class that separates common behaviors from shared behaviors. How could you do this?
//One way would be to create an interface for each behavior, then implement different implementations of that behavior
//By adding these behaviors via interface composition, the interface can then be set to any behavior at construction
//Different Animal subclasses can then also set these behavior objects
//The result is unique behaviors decoupled from both parent class, and child classes, with a uniform interface
//Animal.php - the base parent class
<?php
abstract class Animal{
//unique behaviors...note no instantiation here
protected $moveBehavior;
protected $noiseBehavior;
protected function set_move($moveObject){
$this->moveBehavior = $moveObject;
}
protected function set_noise($noiseObject){
$this->noiseBehavior = $noiseObject;
}
//concrete function shared across all classes
public function eat(){
echo "Animal is eating";
}
//wrappers, separating interface of class from behavior interfaces
public function makeNoise(){
$this->noiseBehavior->makeNoise();
}
public function move(){
$this->moveBehavior->move();
}
}
?>
//AnimalMove.php - Animal behavior interface
<?php
interface AnimalMove{
public function move();
}
?>
//AnimalNoise.php - Animal noise interface
<?php
interface AnimalNoise{
public function makeNoise();
}
?>
//MoveWalk.php - An implementation of move behavior interface
<?php
require_once 'AnimalMove.php';
class MoveWalk implements AnimalMove{
public function move(){
echo "I am walking";
}
}
?>
//MoveWalk.php - Another implementation of move behavior interface
<?php
require_once 'AnimalMove.php';
class MoveFly implements AnimalMove{
public function move(){
echo "I am Flying";
}
}
?>
//Bark.php - An implementation of noise behavior interface
<?php
require_once 'AnimalNoise.php';
class Bark implements AnimalNoise{
public function makeNoise(){
echo "I am barking";
}
}
?>
//Dog.php - An extension of Animal
<?php
require_once 'Animal.php';
//For greater decoupling, could remove default behaviors and set by arg only
require_once 'Bark.php';
require_once 'MoveWalk.php';
class Dog extends Animal{
public function __construct($noise=null, $move=null){
$this->set_move($noise == null ? new MoveWalk() : $move);
$this->set_noise($move == null ? new Bark() : $noise);
}
}
?>
//test.php - testing the above
<?php
require_once 'Dog.php';
require_once 'Bark.php';
require_once 'MoveFly.php';
//create a standard dog with default behaviors
$animal = new Dog();
$animal->makeNoise(); //I am barking
$animal->move(); //I am walking
//create a magical flying doge through injecting behaviors
$bark = new Bark();
$fly = new MoveFly();
$another_animal = new Dog($bark, $fly);
$another_animal->makeNoise(); //I am barking
$another_animal->move(); //I am flying
$animal->eat(); //I am eating
$another_animal->eat(); //I am eating
?>
Python - Scope & Namespaces
#Python has local, enclosing, global, and built-in (LEGB) level scope
#local is the innermost function scope, enclosing is the scope of all functions wrapping the function
#global is module level Scope, built-in holds Python core names
>>> scope = "I am global scope"
>>> def scope_func():
>>> scope = "I am enclosing scope for nested"
>>> def nested():
>>> scope = 'I am local scope for nested'
>>> print(scope) #I am local scope for nested
>>> nested()
>>> print(scope) #I am enclosing scope for nested
>>> scope_func()
>>> print(scope) #I am global scope
#Python does not have an equivalent of block level scope,
#so names defined in 'for', 'while', etc. exist in same scope as statement defined in
>>> for one in range(1):
>>> temp = 'I still exist after this loop'
>>> print(temp)
I still exist after this loop. I am a global var.
#Python name resolution is cascading, checking the innermost scope first, then move up from local->enclosing->global->built-in
#Note that only resolution is cascading and creating a same name var in an inner scope does not change the outer scope var value
>>> global_var = 'global'
>>> def many_scopes():
>>> def inner_scope():
>>> global_var = "different namespace"
>>> def another_scope():
>>> print(global_var)
>>> another_scope()
>>> inner_scope()
>>> global_var = "new value"
>>> many_scopes()
>>> print(global_var)
different namespace
global #resolution cascading but assignment not
#Python allows changing of namespace for variables in global and enclosing/local scope via 'global' and 'nonlocal' keywords
#'global' switches a local/enclosing variable to global namespace
>>> x = 'global'
>>> def global_func():
>>> global x
>>> x = 'I am in global namespace'
>>> global_func()
>>> print(x)
I am in global namespace
#Likewise, Python also has nonlocal variables, in which declaring a var nonlocal
#sets it's namespace to namespace of nearest enclosing function
>>> def non_local():
>>> x = "outermost"
>>> def middle():
>>> x = "middle"
>>> def inner():
>>> nonlocal x
>>> x = "inner"
>>> print(x) #"inner"
>>> inner()
>>> print(x) #"inner" as x inside inner() is in same namespace as middle() due to 'nonlocal'
>>> middle()
>>> print(x) #"outermost"