I am new to Python, stupid question ahead
I need to compare the entries from a MySQL database with ldap. I created a dictionary to hold the corresponding values, when I try to loop through the dictionary and pass them to ldap3 entries to show the results it takes the variable as literal.
for x in values_dict:
value2=values_dict[x]
try:
ldap_conn.entries[0].value2
except Exception as error:
print(error)
else:
print(value2)
attribute 'value2' not found
If I replace value2 with 'sn' or any of the other attributes I have pulled it works fine. I have also played around with exec() but this returns nothing.
for x in values_dict:
value2=values_dict[x]
test1='ldap_conn.entries[0].{}'.format(value2)
try:
result1=exec(test1)
except Exception as error:
print(error)
else:
print(result1)
None
Any ideas?
EDIT 1 : As requested here are the values for values_dict. As stated previously the loop does parse these correctly, ldap does return the attributes, but when I try to use a variable to lookup the attributes from entries the variable is taken literally.
values_dict = {
"First_Name": "givenname",
"Middle_Name": "middlename",
"Last_Name": "sn",
"Preferred_Name": "extensionattribute2",
"Work_Location": "physicaldeliveryofficename",
"Work_City": "l",
"Work_State": "st",
"Work_Postal": "postalcode",
"Work_Email": "mail"
}
The syntax somevariable.someattr, which you are using here:
ldap_conn.entries[0].value2
Always means "access an attribute named someattr of somevariable". It's always interpreted as a literal string. If you need to dynamically access an attribute, use the getattr function:
getattr(ldap_conn.entries[0], value2)
You're not currently assigning that that result anywhere, so you probably want something like:
result1 = getattr(ldap_conn.entries[0], value2)
Related
Why I'm getting this error?
local variable 'type' referenced before assignment
Code:
try:
if type(meeting.modified_date) != bool:
//code
except Exception as e:
raise ValidationError(_(str(e)))
finally:
type = None
if 1:
type = 'auto'
else:
type = 'manual'
I was think some local variable creating this error but after debugging I come to know that this if condition creating an error because of this type().
Empty values on record attributes in Odoo recordsets will always be falsy, except for number fields like float or integer. They will have the value zero and this also is falsy, but zero values can have a meaning in some contexts, so you should always think about the if conditions when checking number values.
Anyways, you can just change your if condition to
if meeting.modified_date:
, because non set date fields are falsy and set date fields are truthy.
One way to get that error.
def _something(self, meeting):
if type(meeting.modified_date) != bool:
pass
#rename it
type = "small"
Edit:
try:
if type(meeting.modified_date) != bool:
//code
except Exception as e:
raise ValidationError(_(str(e)))
finally:
#this is local variable and the fix is
record_type = None
if 1:
record_type = 'auto'
else:
record_type = 'manual'
#and later where type is used it should renamed aswell
The reason you are getting this error is because you assign the global function type to a value in your code. If you do this, then the global function type will be overwritten to be a variable even before the actual assignment in the scope of the name space. Because the python interpreter now treats type as a local variable instead of the global function it is not assigned when you try to call the global function (which is treated as a local variable).
Solution: do not assign names of global functions to variables and rename the variable "type" to something else e.g., object_type.
I mean the code example is basically provided by #Paxmees in the replies. His explanation is a bit difficult to understand. But if you want to see one:
def example_error(var):
if type(var) == bool:
pass
#this produces the error, because you overwrite global function type
type = "string"
def example_fixed(var):
if type(var) == bool:
pass
#fixed do not overwrite global function type:
type_of_var = "string"
In Python there is no switch/case. It is suggested to use dictionaries: What is the Python equivalent for a case/switch statement?
in Python it is good practise to use #property to implement getter/setter: What's the pythonic way to use getters and setters?
So, if I want to build a class with a list of properties to switch so I can get or update values, I can use something like:
class Obj():
"""property demo"""
#property
def uno(self):
return self._uno
#uno.setter
def uno(self, val):
self._uno = val*10
#property
def options(self):
return dict(vars(self))
But calling
o=Obj()
o.uno=10 # o.uno is now 100
o.options
I obtain {'_uno': 100} and not {'uno': 100}.
Am I missing something?
vars is really a tool for introspection, and gives you the local variables of the current space, or in a given object - it is not a good way to get attributes and variables ready for final consumption.
So, your options code must be a bit more sophisticated - one way to go
is to search the class for any properties, and then using getattr to get
the values of those properties, but using the getter code, and
introspect the instance variables, to get any methods attributed directly,
but discard the ones starting with _:
#property
def options(self):
results = {}
# search in all class attributes for properties, including superclasses:
for name in dir(self.__class__):
# obtain the object taht is associated with this name in the class
attr = getattr(self.__class__, name)
if isinstance(attr, property):
# ^ if you want to also retrieve other "property like"
# attributes, it is better to check if it as the `__get__` method and is not callable:
# "if hasattr(attr, '__get__') and not callable(attr):"
# retrieves the attribute - ensuring the getter code is run:
value = getattr(self, name)
results[name] = value
# check for the attributes assigned directly to the instance:
for name, value in self.__dict__.items():
# ^ here, vars(self) could have been used instead of self.__dict__
if not name.startswith("_"):
results[name] = value
return results
about switch..case
On a side note to your question, regarding the "switch...case" construction: please disregard all content you read saying "in Python one should use dictionaries instead of switch/case". This is incorrect.
The correct construct to replace "switch...case" in Python is the "if..elif..else". You can have all the expressiveness one does have with a C-like "switch" with a plain "if-else" tree in Python, and actually, go much beyond that, as the testing expression in if...elif can be arbitrary, and not just a matching value.
option = get_some_user_option()
if option == "A":
...
elif option == "B":
...
elif option in ("C", "D", "E"):
# common code for C, D, E
...
if option == "E":
# specialized code for "E",
else:
# option does not exist.
...
While it is possible to use a dictionary as a call table, and having functions to perform actions in the dictionary values, this construct is obviously not a "drop in" replacement for a plain switch case - starting from the point that the "case" functions can't be written inline in the dictionary, unless they can be written as a lambda function, and mainly
the point that they won't have direct access to the variables on the function calling them.
I have a homework problem which requires me to check if a dictionary value is also a key word, and continue calling values until I find one that is not also a key. The trick is, you can get stuck on a never ending loop.
I tried to remedy this by tracking which values have previously been used in order to be able to kick out of recursion, but the homework problems auto grader does not allow this.
Here is my code:
def rabbit_hole(my_dict, string, new_list = []):
if string in new_list:
return False
try:
new_list.append(string)
value = my_dict[string]
return rabbit_hole(my_dict, value, new_list)
except:
return string
d = {"bat": "pig", "pig": "cat", "cat": "dog", "dog": "ant",
"cow": "bee", "bee": "elk", "elk": "fly", "ewe": "cod",
"cod": "hen", "hog": "fox", "fox": "jay", "jay": "doe",
"rat": "ram", "ram": "rat"}
In the example above, if we execute...
print(rabbit_hole(d, "rat"))
... this shows an example of a never ending loop and I would like it to return False. Is there an obvious reason this doesn't work with the auto grader? Or is there another way to track which keys have already been used?
It could be that your grader is checking for additional arguments to the function and doesn't allow for any.
How about just deleting the dictionary entry you've already checked?
def rabbit_hole(my_dict, string):
try:
value = my_dict[string]
my_dict.pop(string, None)
return rabbit_hole(my_dict, value)
except:
return string
I need a way to get a dictionary value if its key exists, or simply return None, if it does not.
However, Python raises a KeyError exception if you search for a key that does not exist. I know that I can check for the key, but I am looking for something more explicit. Is there a way to just return None if the key does not exist?
You can use dict.get()
value = d.get(key)
which will return None if key is not in d. You can also provide a different default value that will be returned instead of None:
value = d.get(key, "empty")
Wonder no more. It's built into the language.
>>> help(dict)
Help on class dict in module builtins:
class dict(object)
| dict() -> new empty dictionary
| dict(mapping) -> new dictionary initialized from a mapping object's
| (key, value) pairs
...
|
| get(...)
| D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
|
...
Use dict.get
Returns the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
You should use the get() method from the dict class
d = {}
r = d.get('missing_key', None)
This will result in r == None. If the key isn't found in the dictionary, the get function returns the second argument.
If you want a more transparent solution, you can subclass dict to get this behavior:
class NoneDict(dict):
def __getitem__(self, key):
return dict.get(self, key)
>>> foo = NoneDict([(1,"asdf"), (2,"qwerty")])
>>> foo[1]
'asdf'
>>> foo[2]
'qwerty'
>>> foo[3] is None
True
I usually use a defaultdict for situations like this. You supply a factory method that takes no arguments and creates a value when it sees a new key. It's more useful when you want to return something like an empty list on new keys (see the examples).
from collections import defaultdict
d = defaultdict(lambda: None)
print d['new_key'] # prints 'None'
A one line solution would be:
item['key'] if 'key' in item else None
This is useful when trying to add dictionary values to a new list and want to provide a default:
eg.
row = [item['key'] if 'key' in item else 'default_value']
As others have said above, you can use get().
But to check for a key, you can also do:
d = {}
if 'keyname' in d:
# d['keyname'] exists
pass
else:
# d['keyname'] does not exist
pass
You could use a dict object's get() method, as others have already suggested. Alternatively, depending on exactly what you're doing, you might be able use a try/except suite like this:
try:
<to do something with d[key]>
except KeyError:
<deal with it not being there>
Which is considered to be a very "Pythonic" approach to handling the case.
For those using the dict.get technique for nested dictionaries, instead of explicitly checking for every level of the dictionary, or extending the dict class, you can set the default return value to an empty dictionary except for the out-most level. Here's an example:
my_dict = {'level_1': {
'level_2': {
'level_3': 'more_data'
}
}
}
result = my_dict.get('level_1', {}).get('level_2', {}).get('level_3')
# result -> 'more_data'
none_result = my_dict.get('level_1', {}).get('what_level', {}).get('level_3')
# none_result -> None
WARNING: Please note that this technique only works if the expected key's value is a dictionary. If the key what_level did exist in the dictionary but its value was a string or integer etc., then it would've raised an AttributeError.
I was thrown aback by what was possible in python2 vs python3. I will answer it based on what I ended up doing for python3. My objective was simple: check if a json response in dictionary format gave an error or not. My dictionary is called "token" and my key that I am looking for is "error". I am looking for key "error" and if it was not there setting it to value of None, then checking is the value is None, if so proceed with my code. An else statement would handle if I do have the key "error".
if ((token.get('error', None)) is None):
do something
You can use try-except block
try:
value = dict['keyname']
except IndexError:
value = None
d1={"One":1,"Two":2,"Three":3}
d1.get("Four")
If you will run this code there will be no 'Keyerror' which means you can use 'dict.get()' to avoid error and execute your code
If you have a more complex requirement that equates to a cache, this class might come in handy:
class Cache(dict):
""" Provide a dictionary based cache
Pass a function to the constructor that accepts a key and returns
a value. This function will be called exactly once for any key
required of the cache.
"""
def __init__(self, fn):
super()
self._fn = fn
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
value = self[key] = self._fn(key)
return value
The constructor takes a function that is called with the key and should return the value for the dictionary. This value is then stored and retrieved from the dictionary next time. Use it like this...
def get_from_database(name):
# Do expensive thing to retrieve the value from somewhere
return value
answer = Cache(get_from_database)
x = answer(42) # Gets the value from the database
x = answer(42) # Gets the value directly from the dictionary
If you can do it with False, then, there's also the hasattr built-in funtion:
e=dict()
hasattr(e, 'message'):
>>> False
try:
event['ids']
except NameError:
ids = None
This is throwing a KeyError. I just want to check if the event variable exists and set to none or pass the value if it does.
I have also tried to use
if (len(event['ids']) < 1)
but get an error.
Am I missing something? I may or may not have all my event keys passed and want to check for existence.
Use the get method. The second parameter is the default value if the key doesn't exist in the dictionary. It's the standard way to get values from a dictionary when you're not sure if the key exists and you don't want an exception.
ids = event.get('ids', None)
We can check if the key 'key1' exists in the Json dictionary.
{
"key1":"value1"
}
To retrieve the value 'value1' if the key 'key1' exists in the dictionary.
if event.get('key1',None) != None:
value = event.get('key1',None)