# 2.2. Arbitrary Number of Arguments¶

## 2.2.1. Positional arguments¶

• * in this context, is not multiplication in mathematical sense

• * is used for positional arguments

• args is a convention, but you can use any name

• *args unpacks from tuple, list or set

Listing 2.40. Positional arguments passed directly
def echo(a, b, c=0):
print(a)    # 1
print(b)    # 2
print(c)    # 0

echo(1, 2)
Listing 2.41. Positional arguments passed from sequence
def echo(a, b, c=0):
print(a)    # 1
print(b)    # 2
print(c)    # 0

args = (1, 2)
echo(*args)

## 2.2.2. Keyword Arguments¶

• ** in this context, is not power in mathematical sense

• ** is used for keyword arguments

• kwargs is a convention, but you can use any name

• **kwargs unpacks from dict

Listing 2.42. Keyword arguments passed directly
def echo(a, b, c=0):
print(a)    # 1
print(b)    # 2
print(c)    # 0

echo(a=1, b=2)
Listing 2.43. Keyword arguments passed from dict
def echo(a, b, c=0):
print(a)    # 1
print(b)    # 2
print(c)    # 0

kwargs = {'a': 1, 'b': 2}
echo(**kwargs)

## 2.2.3. Positional and Keyword Arguments¶

Listing 2.44. Positional and keyword arguments passed directly
def echo(a, b, c=0):
print(a)    # 1
print(b)    # 2
print(c)    # 0

echo(1, b=2)
Listing 2.45. Positional and keyword arguments passed from sequence and dict
def echo(a, b, c=0):
print(a)    # 1
print(b)    # 2
print(c)    # 0

args = (1,)
kwargs = {'b': 2}

echo(*args, **kwargs)

## 2.2.4. Dynamically create objects¶

from dataclasses import dataclass

MOVEMENT = [
(0,0),
(1,0),
(2,1,1),
(3,2),
(3,3,-1),
(2,3),
]

@dataclass
class Point:
x: int
y: int
z: int = 0

movement = [Point(x,y) for x,y in MOVEMENT]
# ValueError: too many values to unpack (expected 2)

movement = [Point(*coordinates) for coordinates in MOVEMENT]

movement
# [
#   Point(x=0, y=0, z=0),
#   Point(x=1, y=0, z=0),
#   Point(x=2, y=1, z=1),
#   Point(x=3, y=2, z=0),
#   Point(x=3, y=3, z=-1),
#   Point(x=2, y=3, z=0)
# ]

### 2.2.4.1. From sequence¶

DATA = (6.0, 3.4, 4.5, 1.6, 'versicolor')

class Iris:
def __init__(self, sepal_length, sepal_width, petal_length, petal_width, species):
self.sepal_length = sepal_length
self.sepal_width = sepal_width
self.petal_length = petal_length
self.petal_width = petal_width
self.species = species

iris = Iris(*DATA)
iris.species
# 'versicolor'
DATA = [
(6.0, 3.4, 4.5, 1.6, 'versicolor'),
(4.9, 3.1, 1.5, 0.1, "setosa"),
]

class Iris:
def __init__(self, sepal_length, sepal_width, petal_length, petal_width, species):
self.sepal_length = sepal_length
self.sepal_width = sepal_width
self.petal_length = petal_length
self.petal_width = petal_width
self.species = species

def __repr__(self):
return f'{self.species}'

result = [Iris(*row) for row in DATA]
print(result)
# [versicolor, setosa]

### 2.2.4.2. From mapping¶

DATA = {"sepal_length": 6.0, "sepal_width": 3.4, "petal_length": 4.5, "petal_width": 1.6, "species": "versicolor"}

class Iris:
def __init__(self, sepal_length, sepal_width, petal_length, petal_width, species):
self.sepal_length = sepal_length
self.sepal_width = sepal_width
self.petal_length = petal_length
self.petal_width = petal_width
self.species = species

iris = Iris(**DATA)
iris.species
# 'versicolor'
DATA = [
{"sepal_length": 6.0, "sepal_width": 3.4, "petal_length": 4.5, "petal_width": 1.6, "species": "versicolor"},
{"sepal_length": 4.9, "sepal_width": 3.1, "petal_length": 1.5, "petal_width": 0.1, "species": "setosa"},
]

class Iris:
def __init__(self, sepal_length, sepal_width, petal_length, petal_width, species):
self.sepal_length = sepal_length
self.sepal_width = sepal_width
self.petal_length = petal_length
self.petal_width = petal_width
self.species = species

def __repr__(self):
return f'{self.species}'

result = [Iris(**row) for row in DATA]
print(result)
# ['versicolor', 'setosa']

## 2.2.5. Examples¶

### 2.2.5.1. Creating complex numbers¶

Listing 2.46. Defining complex number by passing keyword arguments directly
complex(real=3, imag=5)
# (3+5j)
Listing 2.47. Defining complex number by passing keyword arguments in dict
number = {'real': 3, 'imag': 5}

complex(**number)
# (3+5j)

### 2.2.5.2. Vectors¶

Listing 2.48. Passing vector to the function
def cartesian_coordinates(x, y, z):
print(x)    # 1
print(y)    # 0
print(z)    # 1

vector = (1, 0, 1)

cartesian_coordinates(*vector)

### 2.2.5.3. Point¶

Listing 2.49. Passing vector to the function
def cartesian_coordinates(x, y, z):
print(x)    # 1
print(y)    # 0
print(z)    # 1

point = {'x': 1, 'y': 0, 'z': 1}

cartesian_coordinates(**point)

### 2.2.5.5. Common configuration¶

Listing 2.51. Calling a function which has similar parameters
def draw_line(x, y, color, type, width, markers):
...

draw_line(x=1, y=2, color='red', type='dashed', width='2px', markers='disc')
draw_line(x=3, y=4, color='red', type='dashed', width='2px', markers='disc')
draw_line(x=5, y=6, color='red', type='dashed', width='2px', markers='disc')
Listing 2.52. Passing configuration to the function, which sets parameters from the config
def draw_line(x, y, color, type, width, markers):
...

style = {
'color': 'red',
'type': 'dashed',
'width': '2px',
'markers': 'disc',
}

draw_line(x=1, y=2, **style)
draw_line(x=3, y=4, **style)
draw_line(x=5, y=6, **style)
Listing 2.53. Database connection configuration read from config file
config = {
'host': 'localhost',
'port': 5432,
'database': 'my_database',
}

return ...

connection = database_connect(**config)

### 2.2.5.6. Calling function with all variables from higher order function¶

Listing 2.54. Passing arguments to lower order function. locals() will return a dict with all the variables in local scope of the function.
def template(template, **user_data):
print('Template:', template)
print('Data:', user_data)

def controller(firstname, lastname, uid=0):
permission = ['all', 'everywhere']
return template('user_details.html', **locals())

# template('user_details.html',
#    firstname='Jan',
#    lastname='Twardowski',
#    uid=0,
#    permission=['all', 'everywhere'])

controller('Jan', 'Twardowski')
# Template: user_details.html
# Data: {'firstname': 'Jan',
#        'lastname': 'Twardowski',
#        'uid': 0,
#        'permission': ['all', 'everywhere']}

### 2.2.5.7. Proxy functions¶

Listing 2.55. One of the most common use of *args, **kwargs is for proxy methods.
names=None, index_col=None, usecols=None, squeeze=False, prefix=None,
mangle_dupe_cols=True, dtype=None, engine=None, converters=None,
true_values=None, false_values=None, skipinitialspace=False,
skiprows=None, nrows=None, na_values=None, keep_default_na=True,
na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False,
infer_datetime_format=False, keep_date_col=False, date_parser=None,
dayfirst=False, iterator=False, chunksize=None, compression='infer',
thousands=None, decimal=b'.', lineterminator=None, quotechar='"',
quoting=0, escapechar=None, comment=None, encoding=None, dialect=None,
skipfooter=0, doublequote=True, delim_whitespace=False, low_memory=True,
memory_map=False, float_precision=None):
"""
"""

def my_csv(file, encoding='utf-8', decimal=b',', lineterminator='\n', *args, **kwargs):
lineterminator=lineterminator, *args, **kwargs)

my_csv('iris1.csv')
my_csv('iris2.csv', encoding='iso-8859-2')
my_csv('iris3.csv', encoding='cp1250', verbose=True)
my_csv('iris4.csv', verbose=True, usecols=['Sepal Length', 'Species'])

### 2.2.5.8. Decorator¶

Listing 2.56. Decorators are functions, which get pointer to the decorated function as it's argument, and has closure which gets original function arguments as positional and keyword arguments.

def wrapper(*args, **kwargs):
user = kwargs['request'].user

if user.is_authenticated():
return original_function(*args, **kwargs)
else:
print('Permission denied')

return wrapper

def edit_profile(request):
...

## 2.2.6. Assignments¶

### 2.2.6.1. Function Args/Kwargs Arguments¶

• Complexity level: medium

• Lines of code to write: 15 lines

• Estimated time of completion: 20 min

English
1. Mind the non-functional requirements (see below)

3. Remove species column

5. For each line extract values by splitting lines by coma ,

6. Create result: List[dict] by zipping header and measurements:

• key: column name from the header

• value: measurement at the position

7. Create function mean(**kwargs), function

8. Iterate over result and call mean() by passing arguments as keywords

9. Print mean for each row

10. Compare result with "Output" section (see below)

11. Non-functional requirements:

• Use only str.split() method

• Don't use pandas, numpy or csv etc.

Polish
1. Pobierz plik data/iris.csv i zapisz jako iris.csv

2. Usuń kolumnę species

3. Odseparuj nagłówek od pomiarów

4. Wyciągnij wartości z każdej linii przez podział jej po przecinku ,

5. Stwórz result: List[dict] poprzez scalenie nagłówka i pomiarów z każdego wiersza

• klucz: nazwa kolumny z nagłówka

• wartość: pomiar z odpowiedniej kolumny

6. Stwórz funkcję mean(**kwargs)

7. Iterując po result wywołuj mean() podając argumenty nazwanie

8. Wypisz średnią dla każdego wiersza

9. Porównaj wyniki z sekcją "Output" (patrz poniżej)

10. Wymagania niefunkcjonalne:

• Użyj tylko metody str.split()

• Nie używaj pandas, numpy, csv itp.

Output