how to give object to keyword argument as key [duplicate] - python

This question already has answers here:
Are the keys of a kwargs argument to Python function guaranteed to be type string?
(3 answers)
Closed 2 years ago.
what I want to do is like this
class Foo:
def __init__(self):
self.name = "james"
def foo(**kwargs):
for obj, new_name in kwargs.items():
obj.name = new_name
f = Foo()
foo(f="Tom") # f have to be recognized as an object not a string "f"
as my knowledge, kwargs is a dictionary.
I tested giving an object as key in dictionary. and dictionary can have an object as key.
dd = {f: 12}
print(dd)
>>>
{<__main__.Foo object at 0x00D685D0>: 12}
but when I give an object to function's parameter as key, it becomes just string "f".
Is there the way that doesnt' ruin the original syntax
function(obj=value, obj2=value2, ...)
not like this
function((obj, value), (obj2, value2), ...)
proper process to tuple
EDIT: use this code inside the function
obj = getattr(sys.modules[__name__], f"{obj_name}")

Apparently we cannot have anything else other than strings as key type.
Check detailed answer here : Are the keys of a kwargs argument to Python function guaranteed to be type string?
Check source code here:
https://github.com/python/cpython/blob/2ec70102066fe5534f1a62e8f496d2005e1697db/Python/getargs.c#L1604

kwargs as being a dictionary that maps each keyword to the value that we pass alongside it. That is why when we iterate over the kwargs there doesn’t seem to be any order in which they were printed out.
def myFun(**kwargs):
for key, value in kwargs.items():
print ("%s == %s" %(key, value))
# Driver code
myFun(first ='Geeks', mid ='for', last='Geeks')
you can go for **args
The ** symbol is used before an argument to pass a keyword argument dictionary to a function, this syntax used to successfully run the code when we don’t know how many keyword arguments will be sent to the function.
# function definition
def displayArgument(**arguments):
for arg in arguments.items():
print(arg)
# function call
displayArgument(argument1 ="hello", argument2 = 4,
argument3 ="code")

Related

Pythonic way to get the first passed kwarg without knowing its name? [duplicate]

This question already has answers here:
Access an arbitrary element in a dictionary in Python
(14 answers)
Closed 3 years ago.
I have a function, which has a signature like this:
def func(**kwargs):
The user of that function will call the function with zero or one keyword arguments. If he passes one argument, the name will be foo_id, bar_id, baz_id etc., but I don't know the exact name he will use. The value of the passed argument will be some interger. I still want to take that argument's value and use it.
Currently I'm doing it like this, but I was wondering would there be a cleaner way to achieve this:
def func(**kwargs):
if kwargs:
target_id = list(kwargs.values())[0]
else:
target_id = None
# use target_id here, no worries if it's None
I'm using Python 3.8, so backwards compatibility is not an issue.
Here we are
def func(**kwargs):
target_id = next(iter(kwargs.values()), None)
print(target_id)
func(name_id='name')
func(value_id='value')
func(test_id='test')
func()
Outputs
python test.py
name
value
test
None
Since the dictionary has only one item, and you don't need to keep it in the dictionary, the cleanest way is to use the dict.popitem method. This returns both the argument name and its value as a pair.
def func(**kwarg):
if kwarg:
name, value = kwarg.popitem()
# ...
else:
# ...
Since the caller should supply at most one argument, I recommend explicitly raising an error if it is called with more arguments:
def func(**kwarg):
if len(kwarg) > 1:
raise TypeError(f'Expected at most 1 keyword arg, got {len(kwarg)}.')
elif kwarg:
name, value = kwarg.popitem()
# ...
else:
# ...

how to convert string into argument?

While applying some external module method to a class I need to be able to pass different pairs of arg = 'value' to the function, like:
Ad.nodes.get(id_ = '11974312')
How to pass dicts or tuples to the function, so that it recognises 'id_' (string) as id_ (argument) in
('id_', '11974312') (tuple) or {'id_':'11974312'} (dictionary) ?
Basically, I just need to get id_ out of 'id_'
For your reference, I am trying to use neomodel module for neo4j graph db.
If I understand your question correctly, you are looking for the ** operator.
Example:
kwargs = {'first': 3, 'second': 6}
def add(first, second):
return first + second
print(add(**kwargs) == 9)
This will print True. When you apply ** to a dict argument, it will be decomposed into keyword arguments.
The argument name can be read as string using inspect.signature(function name).parameters.keys() where function name is a name of function, which argument need to be read as string
Example:
import inspect, itertools
dictionary={'id':'David','ip':'11.1.1.20'}
def func(id,ip):
func_argument = list(inspect.signature(func).parameters.keys() )
print(func_argument)
#Print the value from dic for each argument which is key in dict
for i in func_argument:
print(dictionary[i])
func(id=100,ip=200)

pass **kwargs argument to another function with **kwargs

I do not understand the following example, let's say I have these functions:
# python likes
def save(filename, data, **kwargs):
fo = openX(filename, "w", **kwargs) # <- #1
fo.write(data)
fo.close()
# python doesnt like
def save2(filename, data, **kwargs):
fo = openX(filename, "w", kwargs) # <- #2
fo.write(data)
fo.close()
def openX(filename, mode, **kwargs):
#doing something fancy and returning a file object
Why is #1 the right solution and #2 the wrong one? **kwargs is basically a dict, so if I want to pass down the argument to openX I think the correct way would be without ** and just giving the dict. But Python obviously doesn't like the second one and tells me I gave 3 instead of 2 arguments.
So what's the reason behind this?
In the second example you provide 3 arguments: filename, mode and a dictionary (kwargs). But Python expects: 2 formal arguments plus keyword arguments.
By prefixing the dictionary by '**' you unpack the dictionary kwargs to keywords arguments.
A dictionary (type dict) is a single variable containing key-value pairs.
"Keyword arguments" are key-value method-parameters.
Any dictionary can by unpacked to keyword arguments by prefixing it with ** during function call.
Expanding on #gecco 's answer, the following is an example that'll show you the difference:
def foo(**kwargs):
for entry in kwargs.items():
print("Key: {}, value: {}".format(entry[0], entry[1]))
# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})
# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")
Here you can see how unpacking a dictionary works, and why sending an actual dictionary fails
The ** syntax tells Python to collect keyword arguments into a dictionary. The save2 is passing it down as a non-keyword argument (a dictionary object). The openX is not seeing any keyword arguments so the **args doesn't get used. It's instead getting a third non-keyword argument (the dictionary). To fix that change the definition of the openX function.
def openX(filename, mode, kwargs):
pass
For #2
args will be only a formal parameter with dict value, but not a keyword type parameter.
If you want to pass a keyword type parameter into a keyword argument
You need to specific ** before your dictionary, which means **args
check this out for more detail on using **kw
http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/
Because a dictionary is a single value. You need to use keyword expansion if you want to pass it as a group of keyword arguments.
The following code use kwargs and transfer it to another function:
def myprint( kwargs ):
# default values
a = kwargs.get('a', None)
b = kwargs.get('b', None)
# print both
print('a={}, b={}'.format(a,b))
def mytest( **kwargs ):
myprint( kwargs )
mytest()
mytest(b=2)
yields:
a=None, b=None
a=None, b=2

Python notation or operation "**"

I saw the following code:
def __init__(self, fn, **kw):
[setattr(self,k,v) for (k,v) in kw.items()]
......
What does the input argument **kw mean?
kw is bound to a dict mapping keyword argument names to their values.
Try calling
def return_kwargs(**kw):
return kw
as return_kwargs(foo=1, bar="2", baz="hamspamspam").
Suppose you have a dict kw = {'a':1,'b':2}, then calling myfunction(**kw) is equivalent to calling myfunction(a=1,b=2).
This particular construction means what all keyword arguments for the constructor will end up as object attributes.
foo = Foo( func, bar = 1, baz = "aa" )
this would create an object with attribute "bar" set to 1 and "baz" to "aa"
Inside the function, kw is a dictionary that contains all the keyword=value arguments that you gave to your function:
def demo(**kw):
print kw
demo(a=1, b="hello")
Run the above and it will display a dictionary with two keys, a and b. So it works as a way to accept any keyword argument you decide to use when you call the function.
That's what it does. Why would anyone want to do that? Perhaps in a function that calls another function (given as a separate argument), and **kw is to hold options for the second function.

In Python, what does dict.pop(a,b) mean?

class a(object):
data={'a':'aaa','b':'bbb','c':'ccc'}
def pop(self, key, *args):
return self.data.pop(key, *args)#what is this mean.
b=a()
print b.pop('a',{'b':'bbb'})
print b.data
self.data.pop(key, *args) ←------ why is there a second argument?
The pop method of dicts (like self.data, i.e. {'a':'aaa','b':'bbb','c':'ccc'}, here) takes two arguments -- see the docs
The second argument, default, is what pop returns if the first argument, key, is absent.
(If you call pop with just one argument, key, it raises an exception if that key's absent).
In your example, print b.pop('a',{'b':'bbb'}), this is irrelevant because 'a' is a key in b.data. But if you repeat that line...:
b=a()
print b.pop('a',{'b':'bbb'})
print b.pop('a',{'b':'bbb'})
print b.data
you'll see it makes a difference: the first pop removes the 'a' key, so in the second pop the default argument is actually returned (since 'a' is now absent from b.data).
So many questions here. I see at least two, maybe three:
What does pop(a,b) do?/Why are there a second argument?
What is *args being used for?
The first question is trivially answered in the Python Standard Library reference:
pop(key[, default])
If key is in the dictionary, remove it and return its value, else return default.
If default is not given and key is not in the dictionary, a KeyError is raised.
The second question is covered in the Python Language Reference:
If the form “*identifier” is present,
it is initialized to a tuple receiving
any excess positional parameters,
defaulting to the empty tuple. If the
form “**identifier” is present, it is
initialized to a new dictionary
receiving any excess keyword
arguments, defaulting to a new empty
dictionary.
In other words, the pop function takes at least two arguments. The first two get assigned the names self and key; and the rest are stuffed into a tuple called args.
What's happening on the next line when *args is passed along in the call to self.data.pop is the inverse of this - the tuple *args is expanded to of positional parameters which get passed along. This is explained in the Python Language Reference:
If the syntax *expression appears in
the function call, expression must
evaluate to a sequence. Elements from
this sequence are treated as if they
were additional positional arguments
In short, a.pop() wants to be flexible and accept any number of positional parameters, so that it can pass this unknown number of positional parameters on to self.data.pop().
This gives you flexibility; data happens to be a dict right now, and so self.data.pop() takes either one or two parameters; but if you changed data to be a type which took 19 parameters for a call to self.data.pop() you wouldn't have to change class a at all. You'd still have to change any code that called a.pop() to pass the required 19 parameters though.
def func(*args):
pass
When you define a function this way, *args will be array of arguments passed to the function. This allows your function to work without knowing ahead of time how many arguments are going to be passed to it.
You do this with keyword arguments too, using **kwargs:
def func2(**kwargs):
pass
See: Arbitrary argument lists
In your case, you've defined a class which is acting like a dictionary. The dict.pop method is defined as pop(key[, default]).
Your method doesn't use the default parameter. But, by defining your method with *args and passing *args to dict.pop(), you are allowing the caller to use the default parameter.
In other words, you should be able to use your class's pop method like dict.pop:
my_a = a()
value1 = my_a.pop('key1') # throw an exception if key1 isn't in the dict
value2 = my_a.pop('key2', None) # return None if key2 isn't in the dict
>>> def func(a, *args, **kwargs):
... print 'a %s, args %s, kwargs %s' % (a, args, kwargs)
...
>>> func('one', 'two', 'three', four='four', five='five')
a one, args ('two', 'three'), kwargs {'four': 'four', 'five': 'five'}
>>> def anotherfunct(beta, *args):
... print 'beta %s, args %s' % (beta, args)
...
>>> def func(a, *args, **kwargs):
... anotherfunct(a, *args)
...
>>> func('one', 'two', 'three', four='four', five='five')
beta one, args ('two', 'three')
>>>

Categories