[ Web Proxy ]
URL:
Viewing: https://python-course.eu/advanced-python/argument-count.php [Back]  [Original]

12. Argument Count | Advanced | python-course.eu
python-course.eu
Search site:

Live Python classes by highly experienced instructors:

instructor-led training course [instructor-led training course]
Instructor-led training courses by Bernd Klein

  1. Intro to Advanced Python
  2. Recursive Functions
  3. Iterators and Iterables
  4. Generators and Iterators
  5. Lambda Operator, filter, reduce and map
  6. zip introduction and examples
  7. Decorators and Decoration
  8. Memoization and Decorators
  9. Functional Programming OOP
  10. List Comprehension
  11. Function Composition In Python
  12. Currying in Python
  13. Argument Count
  14. Tests, DocTests, UnitTests
  15. Testing with Pytest
  16. Regular Expressions
  17. Advanced Regular Expressions

This website contains a free and extensive online tutorial by Bernd Klein, using material from his classroom Python training courses.

If you are interested in an instructor-led classroom training course, have a look at these Python classes:

instructor-led training course [instructor-led training course]
Instructor-led training course by Bernd Klein at Bodenseo

Image kabliczech - Fotolia.com

This page was written by Bernd Klein.

Bernd is an experienced computer scientist with a history of working in the education management industry and is skilled in Python, Perl, Computer Science, and C++. He has a Dipl.-Informatiker / Master Degree focused in Computer Science from Saarland University.

PDF versions of this site [PDF versions of this site]

PDF logo [PDF logo] PDF version of this site

This website is free of annoying ads. We want to keep it like this. You can help with your donation:

[Go]

The need for donations

12. Argument Count

By Bernd Klein. Last modified: 19 Feb 2025.

Introduction

Arguments and Parameters in a Wordcloud [Arguments and Parameters in a Wordcloud]

Have you ever wondered, "How can I determine the number of arguments in a Python function?" If you're a newcomer to Python, it's unlikely that such a query would even cross your mind. You might simply ask, "What's the point?" or "Why bother". The solution is straightforward: you can either analyze the code or refer to the documentation.

As your proficiency in Python increases, and when you delve into advanced topics like decorators, composing of functions or currying, things look different. You begin crafting code for functions that are unknown at the time of writing So there is no direct way to look at "the function".

Live Python training

instructor-led training course [instructor-led training course]

Enjoying this page? We offer live Python training courses covering the content of this site.

See our Python training courses

See our Machine Learning with Python training courses

An Example

As an example, you can examine the following code for a decorator that tracks how many times a function has been invoked, regardless of the function's argument count or the specific arguments passed to the 'wrapper' function.

def call_counter(func):
    def wrapper(*args, **kwargs):
        helper.calls += 1
        return func(*args, **kwargs)
    helper.calls = 0

    return helper

Let's define the following functions:

def greet(name):
    return f"Hello, {name}!"

def calculate_rectangle_area(length, width):
    return length * width

def calculate_surface_area(length, width, height):
    return 2 * (length * width + width * height + height * length)

def display_info(name, age, *args, **kwargs):
    print(f"Name: {name}")
    print(f"Age: {age}")
    print("Additional Info:")
    for info in args:
        print(info)
    print("Keyword Arguments:")
    for key, value in kwargs.items():
        print(f"{key}: {value}")

Now we decorate these functions with the following decorator:

def describe_parameters(func):
    def wrapper(*args, **kwargs):
        print(f'{args=}, {kwargs=}')
        print(f'{len(args)=}, {len(kwargs)=}')
        return func(*args, **kwargs)
    return wrapper

greet = describe_parameters(greet)
calculate_rectangle_area = describe_parameters(calculate_rectangle_area)
calculate_surface_area = describe_parameters(calculate_surface_area)
display_info = describe_parameters(display_info)
print(greet('Mike'))

OUTPUT:

args=('Mike',), kwargs={}
len(args)=1, len(kwargs)=0
Hello, Mike!
calculate_surface_area(5, 6, 7)

OUTPUT:

args=(5, 6, 7), kwargs={}
len(args)=3, len(kwargs)=0
214
display_info('Emily', 42, 'Berlin', 'Learning Python')

OUTPUT:

args=('Emily', 42, 'Berlin', 'Learning Python'), kwargs={}
len(args)=4, len(kwargs)=0
Name: Emily
Age: 42
Additional Info:
Berlin
Learning Python
Keyword Arguments:

Indeed, based solely on the way these functions are called within the wrapper function, we cannot definitively determine their actual function signatures. The functions could have been defined with individual and different parameter names or with the use of *args and **kwargs, making the exact function signatures unclear.

For example, calculate_surface_area could be defined as def calculate_surface_area(*dimensions) to accept a variable number of dimensions, and display_info might be defined as def display_info(name, age, city, interest) with specific named parameters.

The way the functions are used within the wrapper function doesn't provide enough information to determine the exact function signatures; the details of these signatures would need to be examined within their respective definitions in the code.

The __code__ Attribute

The __code__ attribute of a Python function object contains a wealth of additional information on the arguments. Don't be alarmed by the warning in the help function that states, "Not for the faint of heart." Yet, the help lists only the attributes without explaining them.

One of these is the co_argcount sub-attribute, which returns the number of positional arguments (including arguments with default values).

Let's demonstrate this with the following functions:

def calculate_surface_area(length, width, height):
    return 2 * (length * width + width * height + height * length)

def calculate_surface_area_defaults(length, width=14, height=42):
    return 2 * (length * width + width * height + height * length)

def display_info(name, age, *args, **kwargs):
    print(f"Name: {name}")
    print(f"Age: {age}")
    print("Additional Info:")
    for info in args:
        print(info)
    print("Keyword Arguments:")
    for key, value in kwargs.items():
        print(f"{key}: {value}")
for func in [calculate_surface_area, calculate_surface_area_defaults, display_info]:
    print(f'{func.__name__}.__code__.co_argcount={func.__code__.co_argcount}')

OUTPUT:

calculate_surface_area.__code__.co_argcount=3
calculate_surface_area_defaults.__code__.co_argcount=3
display_info.__code__.co_argcount=2

We will use now the function all-together-now from our chapter Parameters and Arguments

We added also a nested function and a local variable:

def all_together_now(a, /, b, c=11, d=12, *args, kw_only1=42, kw_only2=84, **kwargs):
    local1 = 'whatever'
    def nested_func(x):
        return x + 42
    return f'{a=}, {b=}, {c=}, {d=}, {args=}, {kw_only1=}, {kw_only2=}, {kwargs=}'
all_together_now(2, name='Guido', age=42, kw_only1=99, b=1001)

OUTPUT:

"a=2, b=1001, c=11, d=12, args=(), kw_only1=99, kw_only2=84, kwargs={'name': 'Guido', 'age': 42}"

Let's have a look at the number of positional arguments (including positional-only arguments and arguments with default values):

all_together_now.__code__.co_argcount

OUTPUT:

4

The number 4 stands for the parameters a, b, c and d

Let's have a look at the number of the keyword-only parameters:

all_together_now.__code__.co_kwonlyargcount

OUTPUT:

2
help(all_together_now.__code__)

OUTPUT:

Help on code object:

class code(object)
 |  code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize, flags, codestring, constants, names, varnames, filename, name, qualname, firstlineno, linetable, exceptiontable, freevars=(), cellvars=(), /)
 |  
 |  Create a code object.  Not for the faint of heart.
 |  
 |  Methods defined here:
 |  
 |  __eq__(self, value, /)
 |      Return self==value.
 |  
 |  __ge__(self, value, /)
 |      Return self>=value.
 |  
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |  
 |  __gt__(self, value, /)
 |      Return self>value.
 |  
 |  __hash__(self, /)
 |      Return hash(self).
 |  
 |  __le__(self, value, /)
 |      Return self<=value.
 |  
 |  __lt__(self, value, /)
 |      Return self<value.
 |  
 |  __ne__(self, value, /)
 |      Return self!=value.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  __sizeof__(...)
 |      Size of object in memory, in bytes.
 |  
 |  co_lines(...)
 |  
 |  co_positions(...)
 |  
 |  replace(self, /, *, co_argcount=-1, co_posonlyargcount=-1, co_kwonlyargcount=-1, co_nlocals=-1, co_stacksize=-1, co_flags=-1, co_firstlineno=-1, co_code=None, co_consts=None, co_names=None, co_varnames=None, co_freevars=None, co_cellvars=None, co_filename=None, co_name=None, co_qualname=None, co_linetable=None, co_exceptiontable=None)
 |      Return a copy of the code object with new values for the specified fields.
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  co_argcount
 |  
 |  co_cellvars
 |  
 |  co_code
 |  
 |  co_consts
 |  
 |  co_exceptiontable
 |  
 |  co_filename
 |  
 |  co_firstlineno
 |  
 |  co_flags
 |  
 |  co_freevars
 |  
 |  co_kwonlyargcount
 |  
 |  co_linetable
 |  
 |  co_lnotab
 |  
 |  co_name
 |  
 |  co_names
 |  
 |  co_nlocals
 |  
 |  co_posonlyargcount
 |  
 |  co_qualname
 |  
 |  co_stacksize
 |  
 |  co_varnames

The number 2 stands for the parameters kw_only1 and kw_only2

It's also possible to get the number of positional only parameters:

all_together_now.__code__.co_posonlyargcount

OUTPUT:

1

The only positional only variable, i.e. variables in front of the '/', is a!

What about the count of local variables? How many local variables do you think the functions has? A lot of you are wrong, I am sure! The parameters are counted as local variables as well and the attribute co_nlocals provides us with a count:

all_together_now.__code__.co_nlocals

OUTPUT:

10

You counted to 9? Right? If so, you forgot to see that the function nested_func is local and it's name is considered to be a local variable.

Live Python training

instructor-led training course [instructor-led training course]

Enjoying this page? We offer live Python training courses covering the content of this site.

Upcoming online Courses

See our Python training courses

See our Machine Learning with Python training courses

top


Web Proxy Viewer  |  New URL  |  Original Page