Is there a nice(r) way to have default values in objects - python-3.x

What I'm aiming at is having a object in python3 behaving as normal with regards to attribute access, except that if an attribute is not available through the normal lookup it should fetch/calculate the value in some other way.
I know that one could solve the problem by defining the __getattr__ method:
def __getattr__(self, key):
if key == 'foo':
return calculate_default_foo()
elif key == 'bar':
return getattr(dfltobj, 'bar')
elif key == 'frob':
return 42
raise AttributeError
but that feels so python2 so I wonder if there's a more elegant way to do this in python3. Just defining propertys don't work that well since they completely override accesses to that attribute, but otherwise that would be a nice approach if it had worked.

I don't think there's a way around it, but there is a nice(r) way of modifying __getattr__:
def __getattr__(self, item):
if item == "foo" and not self.foo:
return calculate_default()
return self.__getattribute__(foo)
Hope it helped :)

Related

Access method from different package in Python

I am trying to automate android game. I have so many methods so I break my code in 3 parts.
main, functions and collectors.
I have a method in functions which is:
def search_image(image, confidence=.6, click=True):
location = pyautogui.locateCenterOnScreen(image, confidence=confidence)
if location is not None:
if click:
pyautogui.click(location)
return location
else:
return False
But I cant access it in collectors, like this:
from functions import*
def collect_product():
if search_image(r'Resources\NewOrderAvailable.png') is not False:
search_image(r'Resources\NewOrderAvailable2.png')
for item in range(0, 6):
search_image(r'Resources\Collect.png', confidence=.8)
search_image(r'Resources\Back.png')
search_image(r'Resources\CloseOrderMenu.png')
else:
return False
I got NameError: name 'search_image' is not defined. I need to duplicate that method to make it work. I was wondering what went wrong and how to fix it?
Your function is not an instance of the class. You need to add a self keyword to make it accessible outside.
def search_image(self, image, confidence=.6, click=True):
location = pyautogui.locateCenterOnScreen(image, confidence=confidence)
if location is not None:
if click:
pyautogui.click(location)
return location
else:
return False
Try
import functions
functions.search_image('...')

I am new to python coding and i do not understand how to use a variable from another method

Here is what i have tried:
I do not understand how can i use a variable from another method of same class. Also please explain how can i use a variable from a method in different class. I tried searching but could not find a solution. So what i did to pass the test cases is to copy code from calculate_percentage and paste it in find_grade method. It worked but i think this is the worst method. So please tell a possible solution.
Thanks
#!/bin/python3
#Enter your code here. Read input from STDIN. Print output to STDOUT
class Student:
def __init__(self,roll,name,marks_list):
self.roll=roll
self.name=name
self.marks_list=marks_list
def calculate_percentage(self):
length=len(self.marks_list)
sum=0
for i in self.marks_list:
sum+=i
percent=sum/length
return int(percent)
def find_grade(self,percent):
if percent>=80:
return 'A'
elif percent>=60 and percent<80:
return 'B'
elif percent>=40 and percent<60:
return 'C'
elif percent<40:
return 'F'
if __name__ == '__main__':
roll=int(input())
name=input()
count=int(input())
marks=[]
for i in range(count):
marks.append(int(input()))
s=Student(roll,name,marks)
print(s.calculate_percentage())
print(s.find_grade())
i am getting the error:
print(s.find_grade())
TypeError: find_grade() missing 1 required positional argument: 'percent'
Thanks for every one who answered but i found the answer:
i just need to put self.percent
or percent=self.calculate_percentage() to call the method and use the variables
The assumption would be that the marks are x/100 scale while otherwise your percentage will be incorrect.
As said above, you need to pass the variable percent back to the function since it is not known in the class, it is only returned.
print(s.find_grade(s.calculate_percentage()))
or if the percentage is a class variable you can rewrite it into the class like this:
from statistics import mean
class Student2:
def __init__(self,roll,name,marks_list):
self.roll=roll
self.name=name
self.marks_list=marks_list
def calculate_percentage(self):
self.percent=mean(marks)
return int(self.percent)
def find_grade(self):
if self.percent>=80:
return 'A'
elif self.percent>=60 and self.percent<80:
return 'B'
elif self.percent>=40 and self.percent<60:
return 'C'
elif self.percent<40:
return 'F'
percent = int(0)
# test variables
vRoll = 2
vName = 'student'
vCount= 2
vMarks= [100, 75]
# main
if __name__ == '__main__':
roll=vRoll
name=vName
count=vCount
marks=vMarks
s2=Student2(roll,name,marks)
print(s2.calculate_percentage()) # 87
print(s2.find_grade()) # A

Turning if statement into a single line while setting a variable [duplicate]

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

Can't call a previously declared dictionary though a method

I'm fairly new to python...aka just started.
So i was making a simple game and i'm trying to get a dictionary to work through out a claas and cant get it to work.
class Map(object):
def __init__(self):
self.Eng = {
"1": "Map_Eng()",
"2": "Guard_Fight()",
"3": "Item_Eng()"
}
def enter_room(self):
pass
def exit_room(self):
print("You move onto the next room.")
return self.Eng[1]
The problem is small. Your dictionary has an entry with key "1" (a string), but not with key 1 (a number). To fix your problem, change the line
return self.Eng[1]
to
return self.Eng["1"]

assert wrapper function

So I came across this interesting problem while reviewing code:
class Foo:
def __init__(self, foo_name):
self.foo_doo = getattr(foo_name, 'foo_lists', None)
def assert_foo(self, varname):
assert hasattr(self, 'foo_%s' % varname)
def foobar(self):
assert_foo('doo')
Wonder if wrapping assert to a customized version of your own is faster/better solution then using assert hasattr(...) everytime you need to make sure the attribute is present and not None?
The last line will raise NameError unless changed to
self.assert_foo('doo')
That aside, I do not think assert should be used in the above code with or without the wrapper. The corrected line only checks that self has .foo_doo set, but not that it is not None.
if self.foo_doo is not None:
does both.
If one wants an abbreviated look-first attribute check, one could write
def has_foo(self, name):
return hasattr(self, 'foo_'+name)
def foobar(self):
if has_foo('doo'):
If you also want a non-None check, change the has_foo return to:
return getattr(self, 'foo_'+name, None) is not None
Beyond this, assert in production code should only be used to check internal logic and not runtime conditions affected by users of the code. Users can delete or disable assertions, so code should not depend on assert for its proper operation once released.
In the code above, __init__ sets self.foo_doo to something, but the caller can subsequently delete the attribute. So both the existence and value of the attribute are user-determined run time conditions and not appropriate subjects for assertions.
The TestCase.assertXxx methods of unittest are only used for testing, and when they fail, they do more than just wrap a simple assert.

Resources