For this situation assume there is a table declared with the declarative base called Game, with column names "espn_game_id" and "a_name". There is a session object open under the variable "s". So this works:
s.add(Game(espn_game_id=888, a_name='lol'))
s.commit()
This fails:
n = {"espn_game_id": 888, "a_name": 'lol'}
s.add(Game(n))
s.commit()
This works (assuming there is already an entry with espn_game_id==888):
n = {"a_name": 'lol'}
s.query(Game).filter(Game.espn_game_id==888).update(n)
s.commit()
Why does the second case fail and is there a way to get that type of syntax to work here?
Try to replace:
s.add(Game(n))
with:
s.add(Game(**n))
Let's assume you have function like this:
def foo(**kwargs):
print [item for item in kwargs.items()]
It expects keyword not positional arguments so this will work:
foo(**{'foo': 1, 'bar': 2})
and this will fail:
foo({'foo': 1, 'bar': 2})
For a better explanation you should read *args and **kwargs?
Related
environment:
python 3.6.4
SQLAlchemy==1.2.7
I wrote this code and it works.
1.
filter_data = session.query(MyClass).filter_by(form_type=form_type).one()
and I want to cut function , I wrote below code, but it raise exception.
2.
def myfunc(session, instance, **query):
class_name = type(instance).__name__
try:
ins = session.query(class_name).filter_by(query).one()
...
myfunc(session, new_data, form_type=form_type)
exception is below
ins = session.query(class_name).filter_by(query).one()
TypeError: filter_by() takes 1 positional argument but 2 were given
in function filter_by at query.py of sqlalchemy.orm, I add below code to debug.
def filter_by(self, **kwargs):
l = locals()
print(f'locals are: {l}')
...
it shows,
case 1.
locals are: {'kwargs': {'form_type': 'TAX'}, 'self': <sqlalchemy.orm.query.Query object at 0x1065d8470>}
case 2.
locals are: {'kwargs': {'form_type': 'TAX'}, 'self': <sqlalchemy.orm.query.Query object at 0x10b7b54a8>}
It seems to me the same...
What's the wrong with above two?
replace
cls = instance.__class__
instead of
class_name = type(instance).__name__
and
ins = session.query(cls).filter_by(**query).one()
instead of
ins = session.query(class_name).filter_by(query).one()
session.query expects a sqlalchemy declarative class, not a class name
session.query.filter_by expects variable number of named arguments. since it is an instance method, the first argument is self. The filter parameters can be passed as named arguments through dictionary unpacking, however, if the dict itself is passed, it is like two positional arguments are given to the method, self & query.
Here's a simple example to illustrate this:
class Hal(object):
def hal(self, **kwargs):
return kwargs
hal = Hal()
hal.hal({'a': 1}) # Throws TypeError
hal.hal(**{'a': 1}) # Returns {'a': 1}
Very simple question from a Python newbie:
My understanding is that the keys in a dict are able to be just about any immutable data type. Is it possible to pass an immutable object (e.g., a member of an enum class) as a key in the **kwargs dictionary for a function or a class? I have tried it and the answer seems to be "no":
from enum import Enum
class MyEnum(Enum):
X= 'X'
Y= 'Y'
def func(*args,**kwargs):
pass
func(MyEnum.X = 1)
Output:
"SyntaxError: keyword can't be an expression"
However, there may be something I am missing.
EDIT: Note that I am not trying to make the key equal to MyEnum.X.value (which is a string in this case); I want the key to be the actual Enum object, e.g. MyEnum.X.
You're doing:
func(MyEnum.X = 1)
Here, the problem is MyEnum.X = 1 -- Your keyword (MyEnum.X) is actually an expression (getattr(MyEnum, 'X')), and expressions can't be used as keywords in function calls. In fact, only identifiers can be used as keywords.
To get your call to work, you'll need to use dictionary unpacking like this:
func(**{MyEnum.X.name: 1})
Note, to get the name of the attribute, I needed to do MyEnum.X.name or MyEnum.X.value, depending on how you set up your enum -- In your case, I they are the same thing.
>>> from enum import Enum
>>> class Foo(Enum):
... X = 'X'
...
>>> Foo.X.value
'X'
>>> Foo.X.name
'X'
This won't work, because of the way keyword arguments are being processed. The documentation says:
[...] Next, for each keyword argument, the identifier is used to determine the corresponding slot (if the identifier is the same as the first formal parameter name, the first slot is used, and so on) [...]
So there must be a way to match the key from the dictionary to the formal parameter name. The exception:
keywords must be strings
when you try to pass something that's not a string:
func(**{MyEnum.X: 1})
suggest the simplest case is required: keys must be strings.
A possible workaround is to make implicit things explicit: just create a class that contains all the necessary information you want to pass in its attributes and pass it. The code will surely be more readable.
The answer to my original question is indeed "no". However, thanks to the input from mgilson and BartoszKP and others, the following work around I came up with is not a bad solution, and solves my current problem. I offer it for others to look at who are trying to do something similar:
from enum import Enum
class MyEnum(Enum):
X= 'X'
Y= 'Y'
def func(*args,**kwargs):
#replace kwargs with kwargsNew
kwargsNew = {}
for kwkey, kwvalue in kwargs.items():
try: kwargsNew[MyEnum(kwkey)] = kwvalue
except ValueError: kwargsNew[kwkey] = kwvalue
doStuffWithKwargs(kwargsNew)
def doStuffWithKwargs(k):
for K in k:
print(K)
#Pass the name X or Y as the key;
#all other keys not found in `MyEnum` are treated normally
func(X = 1, Y = 2, Z = 3)
Output:
Z
MyEnum.X
MyEnum.Y
(no errors)
Do you actually want to create an instnace of MyEnum?
myenum = MyEnum()
func(myenum.X = 1)
One alternative I have found is to pass a dict into *args instead of **kwargs, or to assign a dict to kwargs[0] directly:
func({MyEnum.X: 1})
func(kwargs = {MyEnum.X: 1})
(No errors produced)
However, I really don't like either of these methods.
EDIT: See my second answer for a much better solution.
So I have a database with 10 fields(call them a, b, c....j), and I need to create a function "find_use()" that can find and modify records in the database based on any combination of fields given to it as arguments ( ie: find_use(a=="happy", g =="birthday") ). Also, due to privileges, I am not generating the SQL queries directly, but instead use an SQL wrapper the system provides called "selector()" which will locate records based on the same arguments, ie: query = selector(a=="happy", g=="birthday"), which would then return a list of the matching records
So the problem is, since I don't know what arguments find_use() will be receiving, I don't know how to structure the inner call to selector(). Ideally, the call to selector should be created dynamically; something to the effect of:
def find_use(a='',b='',c='',.....j=''):
vars = locals()
for v in vars:
if v.value() != '':
q_string += '{0} == {1},'.format(v.key(),v.value())
query = selector(q_string)
...do something to query...
This, however, will not work since selector does not take a string, but rather arguments in the same format as the find_use() function. How, then, can this be done. I have the feeling this is actually really easy, and I'm just missing something obvious. Any input would be greatly appreciated.
I think you are looking for keyword argument unpacking:
def find_use(**kwargs):
query = selector(**kwargs)
...do something to query...
When defined this way, find_use can receive an arbitrary number of keyword arguments. The keyword arguments are collected in a dict, kwargs.
For example,
def foo(**kwargs):
print(kwargs)
foo(a = 'happy', g = 'birthday')
yields
{'a': 'happy', 'g': 'birthday'}
and if
def bar(a, g):
print(a)
print(g)
then
bar(**{'a': 'happy', 'g': 'birthday'}) # like selector(**kwargs)
yields
happy
birthday
What I want to accomplish:
dct = {'foo':0, 'bar':1, 'baz':2}
def func(**dct):
pass
#function signature is now func(foo=0, bar=1, baz=2)
However, the ** syntax is obviously clashing here between expanding a dict (what I want to do) and declaring a parameter that holds the keyword arguments (what I don't want to do).
Is this possible?
Based on my interpretation of your requirements -- you want to dynamically define a function with a signature that matches the content of adict provided at runtime -- there are two issues here which makes it impractical.
If the arguments are defined at run-time, how can your function reference the variables? Are you planning to build the function body at run-time as well?
dicts are unordered, so you cannot reliably use them to define positional arguments
I suspect this is an XY problem. If you can explain what you're trying to achieve then perhaps we can be of better help.
However, assuming you're trying to assign default keyword arguments using a dict then one way to achieve this would be to use decorators. For example:
def defaultArgs(default_kw):
"decorator to assign default kwargs"
def wrap(f):
def wrapped_f(**kwargs):
kw = {}
kw.update(default_kw) # apply defaults
kw.update(kwargs) # apply from input args
f(**kw) # run actual function with updated kwargs
return wrapped_f
return wrap
You can then use this decorator to assign default keyword arguments to a function that expects only keyword arguments:
defaults = {'foo':0, 'bar':1, 'baz':2}
#defaultArgs(defaults)
def func(**kwargs):
print kwargs # args accessible via the kwargs dict
Results:
func() # prints {'baz': 2, 'foo': 0, 'bar': 1}
func(foo=2) # prints {'baz': 2, 'foo': 2, 'bar': 1}
params = {'bar':1000, 'hello':'world'}
func(**params) # prints {'baz': 2, 'foo': 0, 'bar': 1000, 'hello': 'world'}
Note that you will not be able to use positional arguments:
func(1, 2, 3) # raises TypeError
what you want i believe is eval() link
an answer i gave on a similar question: https://stackoverflow.com/a/11865190/1561176
I'm really not sure what you plan on accomplishing here. The following works (sort of):
def func(**dct):
pass
dct = {'foo':0, 'bar':1, 'baz':2}
func(**dct)
How do you plan on using foo, bar or baz in the function if they're created dynamically? If you give some more details on what you're actually trying to accomplish, we might be able to be a little more helpful.
I just recently have started learning about the wonders of **kwargs but I've hit a stumbling block. Is there a way of sending keywords of a dictionary to a function that does not accept keyword arguments?
Consider the following simple setup:
def two(**kwargs):
return kwargs['second']
def three(**kwargs):
return kwargs['third']
parameterDict = {}
parameterDict['first'] = 1
parameterDict['second'] = 2
parameterDict['third'] = 3
I use some external code that interfaces in the following style:
fitObject = externalCode(two, first=1, second=2)
The problem is: "externalCode" does not accept **kwargs, so is there a smart way of getting the dictionary information into an acceptable form?
Also, the different functions take as parameters different subsets of the parameterDict. So, the function "two" might accept the "first" and "second" parameters, it rejects the "third". And "three" accepts all three.
------------------------------------- EDIT -------------------------------------
People have correctly commented that the above code won't fail -- so I've figured out my problem, and I'm not sure if it's worth a repost or not. I was doing something like this:
def printHair(**kwargs):
if hairColor == 'Black':
print 'Yep!'
pass
personA = {'hairColor':'blue'}
printHair(**personA)
NameError: global name 'hairColor' is not defined
And, apparently the fix is to explicitly include hairColor when defining: printHair(hairColor, **kwargs) in the first place.
>>> def externalCode(two, first=1, second=2):
... print two, first, second
...
>>> params = {'two': 9, 'first': 8, 'second': 7}
>>> externalCode(**params)
9 8 7
You can use the keyword expansion operator (**) to unpack a dictionary into function arguments.
fitObject = externalCode(two, **parameterDict)
How about using get
def printHair(**kwargs):
#check if hair colour is in kwargs
#if it is not you can set a default, otherwise default is None
personA['hairColor'] = kwargs.get('hairColor','Blue')
printHair(**personA)