This is a snippet from Google AppEngine tutorial.
application = webapp.WSGIApplication([('/', MainPage)], debug=True)
I'm not quite sure what debug=True does inside the constructor call.
Does it create a local variable with name debug, assign True to it, and pass it to constructor, or is this a way to set a class instance member variable's value in constructor?
Python functions accept keyword arguments. If you define a function like so:
def my_func(a, b='abc', c='def'):
print a, b, c
You can call it like this:
my_func('hello', c='world')
And the result will be:
hello abc world
You can also support dynamic keyword arguments, using special syntax:
def my_other_func(a, *b, **c):
print a, b, c
*b means that the b variable will take all non-named arguments after a, as a tuple object.
**c means that the c variable will take all named arguments, as a dict object.
If you call the function like this:
my_other_func('hello', 'world', 'what a', state='fine', what='day')
You will get:
hello ('world', 'what a') {'state': 'fine', 'what': 'day'}
Neither -- rather, webapp.WSGIApplication takes an optional argument named debug, and this code is passing the value True for that parameter.
The reference page for WSGIApplication is here and it clearly shows the optional debug argument and the fact that it defaults to False unless explicitly passed in.
As the page further makes clear, passing debug as True means that helpful debugging information is shown to the browser if and when an exception occurs while handling the request.
How exactly that effect is obtained (in particular, whether it implies the existence of an attribute on the instance of WSGIApplication, or how that hypothetical attribute might be named) is an internal, undocumented implementation detail, which we're not supposed to worry about (of course, you can study the sources of WSGIApplication in the SDK if you do worry, or just want to learn more about one possible implementation of these specs!-).
It's using named arguments. See Using Optional and Named Arguments.
Related
How can I find the number of arguments of a Python function? I need to know how many normal arguments it has and how many named arguments.
Example:
def someMethod(self, arg1, kwarg1=None):
pass
This method has 2 arguments and 1 named argument.
The previously accepted answer has been deprecated as of Python 3.0. Instead of using inspect.getargspec you should now opt for the Signature class which superseded it.
Creating a Signature for the function is easy via the signature function:
from inspect import signature
def someMethod(self, arg1, kwarg1=None):
pass
sig = signature(someMethod)
Now, you can either view its parameters quickly by string it:
str(sig) # returns: '(self, arg1, kwarg1=None)'
or you can also get a mapping of attribute names to parameter objects via sig.parameters.
params = sig.parameters
print(params['kwarg1']) # prints: kwarg1=20
Additionally, you can call len on sig.parameters to also see the number of arguments this function requires:
print(len(params)) # 3
Each entry in the params mapping is actually a Parameter object that has further attributes making your life easier. For example, grabbing a parameter and viewing its default value is now easily performed with:
kwarg1 = params['kwarg1']
kwarg1.default # returns: None
similarly for the rest of the objects contained in parameters.
As for Python 2.x users, while inspect.getargspec isn't deprecated, the language will soon be :-). The Signature class isn't available in the 2.x series and won't be. So you still need to work with inspect.getargspec.
As for transitioning between Python 2 and 3, if you have code that relies on the interface of getargspec in Python 2 and switching to signature in 3 is too difficult, you do have the valuable option of using inspect.getfullargspec. It offers a similar interface to getargspec (a single callable argument) in order to grab the arguments of a function while also handling some additional cases that getargspec doesn't:
from inspect import getfullargspec
def someMethod(self, arg1, kwarg1=None):
pass
args = getfullargspec(someMethod)
As with getargspec, getfullargspec returns a NamedTuple which contains the arguments.
print(args)
FullArgSpec(args=['self', 'arg1', 'kwarg1'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={})
import inspect
inspect.getargspec(someMethod)
see the inspect module
func.__code__.co_argcount gives you the number of any arguments BEFORE *args
func.__kwdefaults__ gives you a dict of the keyword arguments AFTER *args
func.__code__.co_kwonlyargcount is equal to len(func.__kwdefaults__)
func.__defaults__ gives you the values of optional arguments that appears before *args
Here is a simple illustration:
>>> def a(b, c, d, e, f=1, g=3, h=None, *i, j=2, k=3, **L):
pass
>>> a.__code__.co_argcount
7
>>> a.__defaults__
(1, 3, None)
>>> len(a.__defaults__)
3
>>>
>>>
>>> a.__kwdefaults__
{'j': 2, 'k': 3}
>>> len(a.__kwdefaults__)
2
>>> a.__code__.co_kwonlyargcount
2
someMethod.func_code.co_argcount
or, if the current function name is undetermined:
import sys
sys._getframe().func_code.co_argcount
inspect.getargspec()
Get the names and default values of a function’s arguments. A tuple of four things is returned: (args, varargs, varkw, defaults). args is a list of the argument names (it may contain nested lists). varargs and varkw are the names of the * and ** arguments or None. defaults is a tuple of default argument values or None if there are no default arguments; if this tuple has n elements, they correspond to the last n elements listed in args.
Changed in version 2.6: Returns a named tuple ArgSpec(args, varargs, keywords, defaults).
See can-you-list-the-keyword-arguments-a-python-function-receives.
Adding to the above, I've also seen that the most of the times help() function really helps
For eg, it gives all the details about the arguments it takes.
help(<method>)
gives the below
method(self, **kwargs) method of apiclient.discovery.Resource instance
Retrieves a report which is a collection of properties / statistics for a specific customer.
Args:
date: string, Represents the date in yyyy-mm-dd format for which the data is to be fetched. (required)
pageToken: string, Token to specify next page.
parameters: string, Represents the application name, parameter name pairs to fetch in csv as app_name1:param_name1, app_name2:param_name2.
Returns:
An object of the form:
{ # JSON template for a collection of usage reports.
"nextPageToken": "A String", # Token for retrieving the next page
"kind": "admin#reports#usageReports", # Th
Good news for folks who want to do this in a portable way between Python 2 and Python 3.6+: use inspect.getfullargspec() method. It works in both Python 2.x and 3.6+
As Jim Fasarakis Hilliard and others have pointed out, it used to be like this:
1. In Python 2.x: use inspect.getargspec()
2. In Python 3.x: use signature, as getargspec() and getfullargspec() were deprecated.
However, starting Python 3.6 (by popular demand?), things have changed towards better:
From the Python 3 documentation page:
inspect.getfullargspec(func)
Changed in version 3.6: This method was previously documented as deprecated in favour of signature() in Python 3.5, but that decision has been reversed in order to restore a clearly supported standard interface for single-source Python 2/3 code migrating away from the legacy getargspec() API.
You get the number of arguments by (replace "function" by the name of your function):
function.__code__.co_argcount ## 2
And the names for the arguments by:
function.__code__.co_varnames ## ('a', 'b')
As other answers suggest, getargspec works well as long as the thing being queried is actually a function. It does not work for built-in functions such as open, len, etc, and will throw an exception in such cases:
TypeError: <built-in function open> is not a Python function
The below function (inspired by this answer) demonstrates a workaround. It returns the number of args expected by f:
from inspect import isfunction, getargspec
def num_args(f):
if isfunction(f):
return len(getargspec(f).args)
else:
spec = f.__doc__.split('\n')[0]
args = spec[spec.find('(')+1:spec.find(')')]
return args.count(',')+1 if args else 0
The idea is to parse the function spec out of the __doc__ string. Obviously this relies on the format of said string so is hardly robust!
inspect.getargspec() to meet your needs
from inspect import getargspec
def func(a, b):
pass
print len(getargspec(func).args)
The accepted answer by Dimitris Fasarakis Hilliard suggests getting parameters in the string format but I think one can make a mistake when parsing this string and thus I created rather a list of the parameters directly using the inspect module
import inspect
def my_function(a,b,c):
#some code
pass
result=list(inspect.signature(my_function).parameters.keys())
print(result)
['a','b','c']
Assuming you may be dealing with class based methods or simply functions, you could do something like the following.
This will automatically subtract one input if the input is a class method (and therefore includes self).
import types
def get_arg_count(fn):
extra_method_input_count=1 if isinstance(fn, types.MethodType) else 0
return fn.__code__.co_argcount-extra_method_input_count
Then you can apply as you need to functions or methods:
def fn1(a, b, c):
return None
class cl1:
def fn2(self, a, b, c):
return None
print(get_arg_count(fn1)) #=> 3
print(get_arg_count(cl1().fn2)) #=> 3
In:
import inspect
class X:
def xyz(self, a, b, c):
return
print(len(inspect.getfullargspec(X.xyz).args))
Out:
4
Note: If xyz wasn't inside class X and had no "self" and just "a, b, c", then it would have printed 3.
For python below 3.5, you may want to replace inspect.getfullargspec by inspect.getargspec in the code above.
This is a solution to getting the number of mandatory arguments of a function (*)
Many of the solutions proposed here do not work for this purpose if some more uncommon parameter specifications are used (positional-only parameters with defaults, keyword-only parameters without defaults, etc.)
from typing import Callable, Any
import inspect
def get_mandatory_argcount(f: Callable[..., Any]) -> int:
"""Get the number of mandatory arguments of a function."""
sig = inspect.signature(f)
def parameter_is_mandatory(p: inspect.Parameter) -> bool:
return p.default is inspect.Parameter.empty and p.kind not in (
inspect.Parameter.VAR_POSITIONAL,
inspect.Parameter.VAR_KEYWORD,
)
return sum(parameter_is_mandatory(p) for p in sig.parameters.values())
# mandatory keyword-only
def f1(b=2, *args, c, d=1, **kwds): pass
print(get_mandatory_argcount(f1))
# positional only with default
def f2(a=1, /, b=3, *args, **kwargs): pass
print(get_mandatory_argcount(f2))
(*) I would have liked to put this as an answer to Programmatically determining amount of parameters a function requires - Python instead, but for some reason this question is marked as duplicate to this one despite it asking specifically about the number of required arguments whereas this question only asks about the general number of arguments.
I'm new to python and I'm tring to make a class for a modul which checking curses in texts.
can someone help please?
import urllib
class Checktext:
def __init__(self, text):
self.text = text
def gettext(self):
file = open(self.text, "r")
filetext = open.read()
for word in filetext.split():
openurl = urllib.request.urlopen("http://www.wdylike.appspot.com/?q=" + word)
output = openurl.read()
truer = "true" in str(output)
print(truer)
s = Checktext(r"C:\Users\Tzach\.atom\Test\Training\readme.txt")
Checktext.gettext()
You declared s as a new Checktext object, so you need to call s.gettext() not an un-instantiated Checktext.gettext(), as that has no self to refer to
The urllib is a package. You have to import the module request that is located in the package:
import urllib.request
The open(filename) return a file object. You want to call the method of that object:
filetext = file.read()
And as G. Anderson wrote, you want to call s.gettext() instead of Checktext.gettext(). The self inside is actually equal to the s outside. If you want to be weird then you actually can use also:
Checktext.gettext(s)
Notice the s passed as your missing parameter. Here Python actually reveals how the Object Oriented things are implemented internally. In majority of OO languages, it is carefully hidden, but calling a method of an object is always internally translated as passing one more special argument that points to the instance of the class, that is the object. When defining a Python method, that special argument is explicitly named self (by convention; you can name it differently -- you can try as the lecture, but you should always keep that convention).
Thinking about it thoroughly, you can get the key idea of the hidden magic of an OO language syntax. The instance of the class (the object) is actually only a portion of memory that stores the data part, and that is passed to the functions that implement the methods. The Checktext.gettext is actually the function, the s is the object. The s.gettext() is actually only a different way to express exactly the same. AS s is the instance of the Checktext class, the fact is stored inside the s. Therefore, the s.gettext() creates the illusion that the rigth code will be called magically. It fits with the trained brain better than the function approach if the s is thought as a tangible something.
Many languages support ad-hoc polymorphism (a.k.a. function overloading) out of the box. However, it seems that Python opted out of it. Still, I can imagine there might be a trick or a library that is able to pull it off in Python. Does anyone know of such a tool?
For example, in Haskell one might use this to generate test data for different types:
-- In some testing library:
class Randomizable a where
genRandom :: a
-- Overload for different types
instance Randomizable String where genRandom = ...
instance Randomizable Int where genRandom = ...
instance Randomizable Bool where genRandom = ...
-- In some client project, we might have a custom type:
instance Randomizable VeryCustomType where genRandom = ...
The beauty of this is that I can extend genRandom for my own custom types without touching the testing library.
How would you achieve something like this in Python?
Python is not a strongly typed language, so it really doesn't matter if yo have an instance of Randomizable or an instance of some other class which has the same methods.
One way to get the appearance of what you want could be this:
types_ = {}
def registerType ( dtype , cls ) :
types_[dtype] = cls
def RandomizableT ( dtype ) :
return types_[dtype]
Firstly, yes, I did define a function with a capital letter, but it's meant to act more like a class. For example:
registerType ( int , TheLibrary.Randomizable )
registerType ( str , MyLibrary.MyStringRandomizable )
Then, later:
type = ... # get whatever type you want to randomize
randomizer = RandomizableT(type) ()
print randomizer.getRandom()
A Python function cannot be automatically specialised based on static compile-time typing. Therefore its result can only depend on its arguments received at run-time and on the global (or local) environment, unless the function itself is modifiable in-place and can carry some state.
Your generic function genRandom takes no arguments besides the typing information. Thus in Python it should at least receive the type as an argument. Since built-in classes cannot be modified, the generic function (instance) implementation for such classes should be somehow supplied through the global environment or included into the function itself.
I've found out that since Python 3.4, there is #functools.singledispatch decorator. However, it works only for functions which receive a type instance (object) as the first argument, so it is not clear how it could be applied in your example. I am also a bit confused by its rationale:
In addition, it is currently a common anti-pattern for Python code to inspect the types of received arguments, in order to decide what to do with the objects.
I understand that anti-pattern is a jargon term for a pattern which is considered undesirable (and does not at all mean the absence of a pattern). The rationale thus claims that inspecting types of arguments is undesirable, and this claim is used to justify introducing a tool that will simplify ... dispatching on the type of an argument. (Incidentally, note that according to PEP 20, "Explicit is better than implicit.")
The "Alternative approaches" section of PEP 443 "Single-dispatch generic functions" however seems worth reading. There are several references to possible solutions, including one to "Five-minute Multimethods in Python" article by Guido van Rossum from 2005.
Does this count for ad hock polymorphism?
class A:
def __init__(self):
pass
def aFunc(self):
print "In A"
class B:
def __init__(self):
pass
def aFunc(self):
print "In B"
f = A()
f.aFunc()
f = B()
f.aFunc()
output
In A
In B
Another version of polymorphism
from module import aName
If two modules use the same interface, you could import either one and use it in your code.
One example of this is from xml.etree.ElementTree import XMLParser
If one does dir() on some builtin callables (class constructors, methods, etc) on CPython 3.4, one finds out that many of them often have a special attribute called __text_signature__, for example:
>>> object.__text_signature__
'()'
>>> int.__text_signature__
>>> # was None
However the documentation for this is nonexistent. Furthermore, googling for the attribute name suggests that there is also another possible special attribute __signature__, though I did not find any built-in functions that would have it.
I do know they are related to the function argument signature, but nothing beyond that, what do their values signify and what is the use of them?
These attributes are there to enable introspection for Python objects defined in C code. The C-API Argument Clinic provides the data, to assist the inspect module when building Signature objects. Introspection of C-API functions was not supported before.
See the internal inspect._signature_fromstr() function on how the __text_signature__ value is used.
Currently, the __text_signature__ attribute is filled from the internal docstring set on objects in the C-API; a simple text search is done for objectname(...)\n--\n\n, where the \n--\n\n is typical of Attribute Clinic-generated documentation strings. Take a look at the type object slots if you wanted to find some examples. Or you could look at the audioop module source to see how the Argument Clinic is being used to define signatures; the Argument Clinic script is run on those when building to generate the docstrings (in the accompanying audioop.c.h file).
The __signature__ attribute, if present, would be a inspect.Signature() object; instead of providing a text version a C-API can provide a fully parsed Signature instance instead.
Quick Summary
Those two attributes are used by the inspect.signature() function to retrieve metadata about a function or method's call signature.
Real-world Application
One use case for manually specifying one of these attributes is to provide useful tooltips for a function that uses *args.
In this example, the randrange() method uses *args to accept a variable number of inputs. However, we want the signature provided to help() and tooltips to show the meaning of each argument so that it matches the corresponding range() function.
import random
class Random(random.Random):
def randrange(self, /, *args):
'Choose a random value from range(start[, stop[, step]]).'
return self.choice(range(*args))
randrange.__text_signature__ = '($self, start, stop=None, step=1, /)'
The __text_signature__ attribute informs the creation of the Signature object:
>>> inspect.signature(Random.randrange)
<Signature (self, start, stop=None, step=1, /)>
This makes the help() output more useful:
>>> help(Random.randrange)
Help on function randrange in module __main__:
randrange(self, start, stop=None, step=1, /)
Choose a random value from range(start[, stop[, step]]).
How can I find the number of arguments of a Python function? I need to know how many normal arguments it has and how many named arguments.
Example:
def someMethod(self, arg1, kwarg1=None):
pass
This method has 2 arguments and 1 named argument.
The previously accepted answer has been deprecated as of Python 3.0. Instead of using inspect.getargspec you should now opt for the Signature class which superseded it.
Creating a Signature for the function is easy via the signature function:
from inspect import signature
def someMethod(self, arg1, kwarg1=None):
pass
sig = signature(someMethod)
Now, you can either view its parameters quickly by string it:
str(sig) # returns: '(self, arg1, kwarg1=None)'
or you can also get a mapping of attribute names to parameter objects via sig.parameters.
params = sig.parameters
print(params['kwarg1']) # prints: kwarg1=20
Additionally, you can call len on sig.parameters to also see the number of arguments this function requires:
print(len(params)) # 3
Each entry in the params mapping is actually a Parameter object that has further attributes making your life easier. For example, grabbing a parameter and viewing its default value is now easily performed with:
kwarg1 = params['kwarg1']
kwarg1.default # returns: None
similarly for the rest of the objects contained in parameters.
As for Python 2.x users, while inspect.getargspec isn't deprecated, the language will soon be :-). The Signature class isn't available in the 2.x series and won't be. So you still need to work with inspect.getargspec.
As for transitioning between Python 2 and 3, if you have code that relies on the interface of getargspec in Python 2 and switching to signature in 3 is too difficult, you do have the valuable option of using inspect.getfullargspec. It offers a similar interface to getargspec (a single callable argument) in order to grab the arguments of a function while also handling some additional cases that getargspec doesn't:
from inspect import getfullargspec
def someMethod(self, arg1, kwarg1=None):
pass
args = getfullargspec(someMethod)
As with getargspec, getfullargspec returns a NamedTuple which contains the arguments.
print(args)
FullArgSpec(args=['self', 'arg1', 'kwarg1'], varargs=None, varkw=None, defaults=(None,), kwonlyargs=[], kwonlydefaults=None, annotations={})
import inspect
inspect.getargspec(someMethod)
see the inspect module
func.__code__.co_argcount gives you the number of any arguments BEFORE *args
func.__kwdefaults__ gives you a dict of the keyword arguments AFTER *args
func.__code__.co_kwonlyargcount is equal to len(func.__kwdefaults__)
func.__defaults__ gives you the values of optional arguments that appears before *args
Here is a simple illustration:
>>> def a(b, c, d, e, f=1, g=3, h=None, *i, j=2, k=3, **L):
pass
>>> a.__code__.co_argcount
7
>>> a.__defaults__
(1, 3, None)
>>> len(a.__defaults__)
3
>>>
>>>
>>> a.__kwdefaults__
{'j': 2, 'k': 3}
>>> len(a.__kwdefaults__)
2
>>> a.__code__.co_kwonlyargcount
2
someMethod.func_code.co_argcount
or, if the current function name is undetermined:
import sys
sys._getframe().func_code.co_argcount
inspect.getargspec()
Get the names and default values of a function’s arguments. A tuple of four things is returned: (args, varargs, varkw, defaults). args is a list of the argument names (it may contain nested lists). varargs and varkw are the names of the * and ** arguments or None. defaults is a tuple of default argument values or None if there are no default arguments; if this tuple has n elements, they correspond to the last n elements listed in args.
Changed in version 2.6: Returns a named tuple ArgSpec(args, varargs, keywords, defaults).
See can-you-list-the-keyword-arguments-a-python-function-receives.
Adding to the above, I've also seen that the most of the times help() function really helps
For eg, it gives all the details about the arguments it takes.
help(<method>)
gives the below
method(self, **kwargs) method of apiclient.discovery.Resource instance
Retrieves a report which is a collection of properties / statistics for a specific customer.
Args:
date: string, Represents the date in yyyy-mm-dd format for which the data is to be fetched. (required)
pageToken: string, Token to specify next page.
parameters: string, Represents the application name, parameter name pairs to fetch in csv as app_name1:param_name1, app_name2:param_name2.
Returns:
An object of the form:
{ # JSON template for a collection of usage reports.
"nextPageToken": "A String", # Token for retrieving the next page
"kind": "admin#reports#usageReports", # Th
Good news for folks who want to do this in a portable way between Python 2 and Python 3.6+: use inspect.getfullargspec() method. It works in both Python 2.x and 3.6+
As Jim Fasarakis Hilliard and others have pointed out, it used to be like this:
1. In Python 2.x: use inspect.getargspec()
2. In Python 3.x: use signature, as getargspec() and getfullargspec() were deprecated.
However, starting Python 3.6 (by popular demand?), things have changed towards better:
From the Python 3 documentation page:
inspect.getfullargspec(func)
Changed in version 3.6: This method was previously documented as deprecated in favour of signature() in Python 3.5, but that decision has been reversed in order to restore a clearly supported standard interface for single-source Python 2/3 code migrating away from the legacy getargspec() API.
You get the number of arguments by (replace "function" by the name of your function):
function.__code__.co_argcount ## 2
And the names for the arguments by:
function.__code__.co_varnames ## ('a', 'b')
As other answers suggest, getargspec works well as long as the thing being queried is actually a function. It does not work for built-in functions such as open, len, etc, and will throw an exception in such cases:
TypeError: <built-in function open> is not a Python function
The below function (inspired by this answer) demonstrates a workaround. It returns the number of args expected by f:
from inspect import isfunction, getargspec
def num_args(f):
if isfunction(f):
return len(getargspec(f).args)
else:
spec = f.__doc__.split('\n')[0]
args = spec[spec.find('(')+1:spec.find(')')]
return args.count(',')+1 if args else 0
The idea is to parse the function spec out of the __doc__ string. Obviously this relies on the format of said string so is hardly robust!
inspect.getargspec() to meet your needs
from inspect import getargspec
def func(a, b):
pass
print len(getargspec(func).args)
The accepted answer by Dimitris Fasarakis Hilliard suggests getting parameters in the string format but I think one can make a mistake when parsing this string and thus I created rather a list of the parameters directly using the inspect module
import inspect
def my_function(a,b,c):
#some code
pass
result=list(inspect.signature(my_function).parameters.keys())
print(result)
['a','b','c']
Assuming you may be dealing with class based methods or simply functions, you could do something like the following.
This will automatically subtract one input if the input is a class method (and therefore includes self).
import types
def get_arg_count(fn):
extra_method_input_count=1 if isinstance(fn, types.MethodType) else 0
return fn.__code__.co_argcount-extra_method_input_count
Then you can apply as you need to functions or methods:
def fn1(a, b, c):
return None
class cl1:
def fn2(self, a, b, c):
return None
print(get_arg_count(fn1)) #=> 3
print(get_arg_count(cl1().fn2)) #=> 3
In:
import inspect
class X:
def xyz(self, a, b, c):
return
print(len(inspect.getfullargspec(X.xyz).args))
Out:
4
Note: If xyz wasn't inside class X and had no "self" and just "a, b, c", then it would have printed 3.
For python below 3.5, you may want to replace inspect.getfullargspec by inspect.getargspec in the code above.
This is a solution to getting the number of mandatory arguments of a function (*)
Many of the solutions proposed here do not work for this purpose if some more uncommon parameter specifications are used (positional-only parameters with defaults, keyword-only parameters without defaults, etc.)
from typing import Callable, Any
import inspect
def get_mandatory_argcount(f: Callable[..., Any]) -> int:
"""Get the number of mandatory arguments of a function."""
sig = inspect.signature(f)
def parameter_is_mandatory(p: inspect.Parameter) -> bool:
return p.default is inspect.Parameter.empty and p.kind not in (
inspect.Parameter.VAR_POSITIONAL,
inspect.Parameter.VAR_KEYWORD,
)
return sum(parameter_is_mandatory(p) for p in sig.parameters.values())
# mandatory keyword-only
def f1(b=2, *args, c, d=1, **kwds): pass
print(get_mandatory_argcount(f1))
# positional only with default
def f2(a=1, /, b=3, *args, **kwargs): pass
print(get_mandatory_argcount(f2))
(*) I would have liked to put this as an answer to Programmatically determining amount of parameters a function requires - Python instead, but for some reason this question is marked as duplicate to this one despite it asking specifically about the number of required arguments whereas this question only asks about the general number of arguments.