Is it possible to call methods from specific objects using a variable? - python

I've been wondering this for a time now and it seems like something Python would have, but is it possible to call the same method from different using code similar to this?
Here's the class I'm using to test this:
class Test():
def __init__(self,foo):
self.foo = foo
def method_a():
print(self.foo)
And here's the running code:
import classTest
object1 = classTest.Test("Unn")
object2 = classTest.Test("Tss")
runThis = input("Type in either object1 or object2:")
runThis.method_a()
I get this:
AttributeError: 'str' object has no attribute 'method_a'
Have I done something wrong? Or does Python lack that functionality?

Put your objects in a dictionary:
objects = {}
objects['object1'] = classTest.Test("Unn")
objects['object2'] = classTest.Test("Tss")
runThis = input("Type in either object1 or object2:")
objects[runThis].method_a()
You can also access the module globals with the globals() function, which gives you a dictionary too, but most of the time you want to use a dedicated dictionary instead.

You can use globals to access your variables by name:
globals()[runThis].method_a()

Also it might be helpful in some case.
import gc
for obj in gc.get_objects():
if isinstance(obj, Test):
print obj

You could also use this:
import classTest
object1 = classTest.Test("Unn")
object2 = classTest.Test("Tss")
runThis = eval(raw_input("Type in either object1 or object2:"), globals())
runThis.method_a()

Related

Data descriptors for python module

I know you can define data descriptors for a class instance using the __get__ and __set__ methods. Is it possible to define something similar for an imported module ?
Use case:
I have a large test file with a lot of dictionaries defined in a
test_data.py (legacy code), therefore all of them are **mutable and cannot be modified by individual tests without using deepcopy
I want to be able to modify these dictionaries
Without re-writing the data into classes
without calling deepcopy in tests.
Test data:
expected_response_1 = dict(status=False)
Test case:
from test import test_data
data = test_data.expected_response_1
data['status'] = True
print(data)
# --> {'status': True}
print(test_data.expected_response_1)
# --> {'status': False}
Is there any *python-magic i can use to always return a copy of expected_response_1
This cannot be done directly since descriptors need to be defined as class attributes (which mean you'd have to add them to the builtin module type, which is not allowed).
BUT you can just use a simple wrapper around your test_data module and use the __getattr__() magic method:
class DataWrapper(object):
def __init__(self, module):
self._module = module
def __getattr__(self, name):
val = getattr(self._module, name)
return copy.deepcopy(val)
from test import test_data
test_data = WrapperData(test_data)
I think you mean that dictionaries are mutable, and you want to change the dictionaries in the test case without modifying the original dictionary.
You can indeed use deepcopy, which is not a bad practice at all. You can also change the test_data module to provide the dictionaries as class properties: this will return a new dictionary every time, with the original content:
test_data.py:
class test_data:
#property
#staticmethod
def expected_response_1:
return dict(status=False)
test_case.py:
from test.test_data import test_data
data = test_data.expected_response_1
data['status'] = True
print(data)
# --> {'status': True}
print(test_data.expected_response_1)
# --> {'status': False}

When using Python classes as program configuration structures (which includes inherited class attributes), a good way to save/restore?

Let's say I have a (simplified) class as below. I am using it for a program configuration (hyperparameters).
# config.py
class Config(object): # default configuration
GPU_COUNT = 1
IMAGES_PER_GPU = 2
MAP = {1:2, 2:3}
def display(self):
pass
# experiment1.py
from config import Config as Default
class Config(Default): # some over-written configuration
GPU_COUNT = 2
NAME='2'
# run.py
from experiment1 import Config
cfg = Config()
...
cfg.NAME = 'ABC' # possible runtime over-writing
# Now I would like to save `cfg` at this moment
I'd like to save this configuration and restore later. The member functions must be out of concern when restoring.
1. When I tried pickle:
import pickle
with open('cfg.pk', 'rb') as f: cfg = pickle.load(f)
##--> AttributeError: Can't get attribute 'Config' on <module '__main__'>
I saw a solution using class_def of Config, but I wish I can restore the configuration without knowing the class definition (eg, export to dict and save as JSON)
2. I tried to convert class to dict (so that I can export as JSON)
cfg.__dict__ # {'NAME': 'ABC'}
vars(cfg) # {'NAME': 'ABC'}
In both cases, it was difficult to access attributes. Is it possible?
The question's title is "how to convert python class to dict", but I suspect you are really just looking for an easy way to represent (hyper)parameters.
By far the easiest solution is to not use classes for this. I've seen it happen on some machine learning tutorials, but I consider it a pretty ugly hack. It breaks some semantics about classes vs objects, and the difficulty pickling is a result from that. How about you use a simple class like this one:
class Params(dict):
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
def __getstate__(self):
return self
def __setstate__(self, state):
self.update(state)
def copy(self, **extra_params):
return Params(**self, **extra_params)
It can do everything the class approach can. Predefined configs are then just objects you should copy before editing, as follows:
config = Params(
GPU_COUNT = 2,
NAME='2',
)
other_config = config.copy()
other_config.GPU_COUNT = 4
Or alternatively in one step:
other_config = config.copy(
GPU_COUNT = 4
)
Works fine with pickle (although you will need to have the Params class somewhere in your source), and you could also easily write load and save methods for the Params class if you want to use JSON.
In short, do not use a class for something that really is just an object.
Thankfully, #evertheylen's answer was great to me. However, the code returns error when p.__class__ = Params, so I slightly changed as below. I think it works in the same way.
class Params(dict):
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
def __getstate__(self):
return self
def __setstate__(self, state):
self.update(state)
def copy(self, **extra_params):
lhs = Params()
lhs.update(self)
lhs.update(extra_params)
return lhs
and you can do
config = Params(
GPU_COUNT = 2,
NAME='2',
)
other_config = config.copy()
other_config.GPU_COUNT = 4

How to modify variables in another python file?

windows 10 - python 3.5.2
Hi, I have the two following python files, and I want to edit the second file's variables using the code in the first python file.
firstfile.py
from X.secondfile import *
def edit():
#editing second file's variables by user input
if Language == 'en-US':
print('language is English-us')
elif Language == 'en-UK':
print('language is English-uk')
secondfile.py
Language = 'en-US'
i can add some variables to it by following code, but how can i edit one ?
with open("secondfile.py","a") as f:
f.write("Language = 'en-US'")
Any ideas how to do that?
You can embed the Language in a class in the second file that has a method to change it.
Module 2
class Language:
def __init__(self):
self.language = 'en-US'
def __str__(self):
return self.language
def change(self, lang):
assert isinstance(lang, str)
self.language = lang
language = Language()
Then import the "language," and change it with the change method.
Module 1
from module2 import language
print(language)
language.change("test")
print(language)
This can be done to edit a variable in another file:
import X.secondfile
X.secondfile.Language = 'en-UK'
However, I have two suggestions:
Don't use import * - it pollutes the namespace with unexpected
names
Don't use such global variables, if they are not constants. Some code will read the value before it is changed and some afterwards. And none will expect it to change.
So, rather than this, create a class in the other file.
class LanguagePreferences(object):
def __init__(self, langcode):
self.langcode = langcode
language_preferences = LanguagePreferences('en-UK')

python defining multiple classes with decorators

I have the base class:
class BaseGameHandler(BaseRequestHandler):
name = 'Base'
def get(self):
self.render(self.name + ".html")
Now, I need to define a few subclasses of this but the thing is, they have to have a decorator. Equivalent code would be:
#route('asteroid')
class AsteroidGameHandler(BaseGameHandler):
name = 'asteroid'
#route('blah')
class BlahGameHandler(BaseGameHandler):
name = 'blah'
and maybe a few more.
A little background here: This is a tornado web app and the #route decorator allows you to map /blah to BlahGameHandler. This code maps /blah to BlahGameHandler and /asteroid to AsteroidGameHandler.
So I thoughtI should use metaprogramming in python and define all these classes on the fly. I tried the following which doesn't work(and by doesn't work I mean the final web-app throws 404 on both /asteroid and /blah):
game_names = ['asteroid', 'blah']
games = list([game, type('%sGameHandler' % (game.title()), (BaseGameHandler,), {'name': game})] for game in game_names)
for i in xrange(len(games)):
games[i][1] = route(games[i][0])(games[i][1])
What am I missing? Aren't these two codes equivalent when run?
The library that you use only looks for global class objects in your module.
Set each class as a global; the globals() function gives you access to your module namespace as a dictionary:
for i in xrange(len(games)):
globals()[games[i][1].__name__] = route(games[i][0])(games[i][1])
The include() code does not look for your views in lists.
To be specific, include() uses the following loop to detect handlers:
for member in dir(module):
member = getattr(module, member)
if isinstance(member, type) and issubclass(member, web.RequestHandler) and hasattr(member, 'routes'):
# ...
elif isinstance(member, type) and issubclass(member, web.RequestHandler) and hasattr(member, 'route_path'):
# ...
elif isinstance(member, type) and issubclass(member, web.RequestHandler) and hasattr(member, 'rest_route_path'):
# ...
dir(module) only considers top-level objects.

Getting error message when trying to attach a class to an object

i have a little problem when i try to attach a class to an object in python. I have a textfile 'file', which is seperated into a list for each line. The program will read every line and print a name and a longname. Imagine that the textfile look like this:
"John '\n' John Travolta" (...)
Here's my bit of code:
class Name:
def __init__(self, name, longname):
self.name=name
self.longname=longname
def __str__(self):
s="Name:"+self.name
s+="\n Longname:"+self.longname
def func():
for line in file:
name=line[:1]
longname=line['\n':]
c=Name(name, longname)
c.func()
I get the error message that my 'name' and 'longname' is not defined but I did this with my function??? :(
It works if I put the function outside the class, like this:
def func():
for line in file:
name=line[:1]
longname=line['\n':]
c=Name(name, longname)
print c
Need help!
You need to assign something to name and longname before you can use them:
name = 'foo'
longname = 'foo bar'
c=Name(name, longname)
c.func()
but I did this with my function?
No.
Firstly, you didn't call your function yet. The function call is after the line that gives the error.
Secondly, the function has its own scope. The name there is different from the global name.
I don't think it makes any sense to move your func method inside the class definition. The code that you said works is a better way to do it.

Categories

Resources