Python global name not defined - python

I'm trying to test the following simple object:
class WebCorpus(object):
def __init__(self):
_index = {}
_graph = {}
_ranks = {}
_corpusChanged = False
def lookup(self, keyword):
if keyword in _index:
return _index[keyword]
return None
# (some irrelevant code)
With:
from WebCorpus import WebCorpus
def test_engine():
print "Testing..."
content = """This is a sample webpage with
two links that lead nowhere special."""
outlinks = ["http://www.example.com", "http://www.go.to"]
corpus = WebCorpus()
assert corpus.lookup("anything") == None
#(some more code)
test_engine()
But it gives me an error: NameError: global name '_index' is not defined. I don't understand this, _index is clearly defined in the __init__ !? What is my mistake here?
Help appreciated.

In order to set class variables in the class method, you should use self:
class WebCorpus(object):
def __init__(self):
self._index = {}
self._graph = {}
self._ranks = {}
self._corpusChanged = False
def lookup(self, keyword):
if keyword in self._index:
return self._index[keyword]
return None
Or, you can simplify the code and set variables like this (I've also simplified lookup method):
class WebCorpus(object):
_index = {}
_graph = {}
_ranks = {}
_corpusChanged = False
def lookup(self, keyword):
return self._index.get(keyword)
Note, the second example is not equivalent to the first one, because class-level variables are used, see comments below.

What's happening here is that it's defining _index but then losing it after the __init__ is run. You should append self to everything, so it's self._index, etc. This goes for the entire class, not just in the __init__.

Related

simple class as data container: Howto?

I want a class with static attributes that can be stored using one or more get methods from outside and the stored values can be retrieved using one or more get methods
class contract_data:
contract_header = dict()
contract_item = dict()
contract_schedule = dict()
# #staticmethod
def put_header(line:list,findex:dict):
contract_header[line[findex['VBELN_VA']]] = {'KNKLI':[line[findex['KNKLI']]],
'VTWEG':[line[findex['VTWEG']]],
'SPART':[line[findex['SPART']]],
'VKBUR':[line[findex['VKBUR']]],
'VKGRP':[line[findex['VKGRP']]],
'BSTKD':[line[findex['BSTKD']]]
}
def get_header(keyval:str)->dict:
return contract_header[keyval]
# #staticmethod
def put_item(line: list, findex: dict):
return
#staticmethod
def put_schedule(line: list, findex: dict):
return
I expected that calling contract_data.put_header(line,findex) I could store values in contract_data attribute contract_header. But it fails with runtime error
in put_header:
contract_header[line[findex['VBELN_VA']]] = {'KNKLI':[line[findex['KNKLI']]],
NameError: name 'contract_header' is not defined. Did you mean: 'contract_data'?
I played around with #staticmethod and .self or self. with no success.
I expect the class attributes, the dictionaries can be used within the class but not outside.
Your dicts are not global variables; they're class attributes, and as such need to be accessed from the class. That means your static methods need to be defined as class methods.
class contract_data:
contract_header = dict()
contract_item = dict()
contract_schedule = dict()
#classmethod
def put_header(cls, line: list, findex: dict):
cls.contract_header[line[findex['VBELN_VA']]] = {
k: [line[findex[k]]]
for k in ['KNKLI', 'VTWEB', 'SPART', 'VKBUR', 'VKGRP', 'BSTKD']}
#classmethod
def get_header(cls, keyval: str)->dict:
return cls.contract_header[keyval]
...

How to dynamically convert non-existing class member functions to existing ones

I have a class:
class DataReader:
def get_data(self, name):
# get data of given name
It's OK that I use it as following:
reader = DataReader()
a = reader.get_data('a')
b = reader.get_data('b')
c = reader.get_data('c')
...
Is it possible that I write codes like following:
a = reader.get_a()
b = reader.get_b()
c = reader.get_c()
For current codes, it will fail since class DataReader has no methods like get_a(). What I want is, do something to let DataReader support method like get_a, and automatically convert it to self.get_data('a'), without really define get_xxx methods one by one.
Here, the a, b, c can be any string, and I cannot know all of them while defining DataReader class. So, let me ask my question in another way: is there some shortcut way to let DataReader support all (infinity) get_xxx methods (here xxx can be any string), as if I defined infinity methods like:
class DataReader:
def get_a(self): return self.get('a')
def get_b(self): return self.get('b')
...
def get_z(self): return self.get('z')
def get_aa(self): return self.get('aa')
...
def get_asdf(self): return self.get('asdf')
...
def get_okjgoke(self): return self.get('okjgoke')
...
One method is having the DataReader to define __getattr__ special method (that method is invoked when attribute is not found inside the object):
class DataReader:
def __init__(self, data):
self.items = data.copy()
def __getattr__(self, attr):
if attr.startswith('get_'):
return lambda: self.items[attr.split('get_')[-1]]
raise AttributeError('Attribute "{}" not found.'.format(attr))
d = DataReader({'a':1, 'b':2})
print(d.get_a())
print(d.get_b())
Prints:
1
2
Your approach of passing the name to get_data seems pretty reasonable to me. But if you insist on using the attribute based lookups, you can override __getattr__ and use get_data to in there for lookups e.g.:
class DataReader:
def __getattr__(self, attr):
parts = attr.partition('_')
if parts[0] == 'get' and parts[-1] != 'data':
return self.get_data(parts[-1])
return super().__getattr__(attr)
def get_data(self, name):
return name
Now you can use Foo().get_a to get Foo().get_data('a').
If you want get the value from a callable like Foo().get_a() instead of Foo().get_a, you can use tuck in a lambda:
class DataReader:
def __getattr__(self, attr):
parts = attr.partition('_')
if parts[0] == 'get' and parts[-1] != 'data':
return lambda: self.get_data(parts[-1])
return super().__getattr__(attr)
def get_data(self, name):
return name
Now you can do Foo().get_a().

Is it possible to call variables of a different object of the same class in Python?

I would like to create a function that takes in a different object from the same class, and then alter that object's parameters. However, when I try to alter that object, instead of altering that object's variable it alter's the local object's.
For example:
class MyClass():
item = ''
def __init__(self):
self.item = ''
def function(self, otherObject):
otherObject.item = self.item
Heres my code:
class Taxonomy:
categoryName = ''
itemList = []
def __init__(self, itemList = []):
self.categoryName = categoryName
self.itemList = itemList
def addTaxonomy(self, tax):
self.taxonomy_tree[''][self.categoryName][tax.categoryName]
self.itemList.clear()
self.itemList.append(self.categoryName)
tax.itemList.clear()
For some reason the 'tax.itemList.clear()' clears both itemLists.
Its because itemList all point to the same instance of list. In python creating a default argument value with a mutable type is not a good idea. Take def f(x=[]): pass. This function share the same list for all call of f where no argument x is passed.
this code illustrate better what I am trying to say.
def f(x=[]):
x.append(1)
return x
f()
print f() # ouput: [1, 1]
Hopefully you can easily refactor using a default None value for your param.
def f(x=None):
x = x or []
x.append(1)
return x
f()
print f() # ouput: [1]
A specific solution to your problem would be:
def __init__(self, itemList = None):
self.categoryName = categoryName
self.itemList = itemList or []

Dynamically generate method from string?

I have a dict of different types for which I want to add a simple getter based on the name of the actual parameter.
For example, for three storage parameters, let's say:
self.storage = {'total':100,'used':88,'free':1}
I am looking now for a way (if possible?) to generate a function on the fly with some meta-programming magic.
Instead of
class spaceObj(object):
def getSize(what='total'):
return storage[what]
or hard coding
#property
def getSizeTotal():
return storage['total']
but
class spaceObj(object):
# manipulting the object's index and magic
#property
def getSize:
return ???
so that calling mySpaceObj.getSizeFree would be derived - with getSize only defined once in the object and related functions derived from it by manipulating the objects function list.
Is something like that possible?
While certainly possible to get an unknown attribute from a class as a property, this is not a pythonic approach (__getattr__ magic methods are rather rubyist)
class spaceObj(object):
storage = None
def __init__(self): # this is for testing only
self.storage = {'total':100,'used':88,'free':1}
def __getattr__(self, item):
if item[:7] == 'getSize': # check if an undefined attribute starts with this
return self.getSize(item[7:])
def getSize(self, what='total'):
return self.storage[what.lower()]
print (spaceObj().getSizeTotal) # 100
You can put the values into the object as properties:
class SpaceObj(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
storage = {'total':100,'used':88,'free':1}
o = SpaceObj(**storage)
print o.total
or
o = SpaceObj(total=100, used=88, free=1)
print o.total
or using __getattr__:
class SpaceObj(object):
def __init__(self, **kwargs):
self.storage = kwargs
def __getattr__(self,name):
return self.storage[name]
o = SpaceObj(total=100, used=88, free=1)
print o.total
The latter approach takes a bit more code but it's more safe; if you have a method foo and someone create the instance with SpaceObj(foo=1), then the method will be overwritten with the first approach.
>>> import new
>>> funcstr = "def wat(): print \"wat\";return;"
>>> funcbin = compile(funcstr,'','exec')
>>> ns = {}
>>> exec funcbin in ns
>>> watfunction = new.function(ns["wat"].func_code,globals(),"wat")
>>> globals()["wat"]=watfunction
>>> wat()
wat

Custom class with recursion in methods, global name not defined

I'm trying to implement a method for which is necessary to use recursion, but every time, I get the global name not defined error
My class look like this:
class MyClass(object):
def _init_(self, name=None, content=None):
self.name = name
self.content = content
It's a node class, name it's just a text string and content a list of it's children (they are nodes too), is initialized as None but the construction function that builds the tree give them a blank list if they have no children. The class works fine and so does the function but if I try to add recurtion to methods they just don't work, even if they work just fine as a standalone function, i.e.:
def get_nodes(self):
c = []
c.append(self.name)
if self.content != []:
for a in self.content:
c.extend(get_nodes(a))
return c
I know this is possible, what am I doing wrong?
You need to do a.get_nodes().
Also the initialization method is called __init__, not _init_ (two underscores on both ends).
Edit: If you won't show your code, we can't tell you what's wrong with your code. This code works for me:
class MyClass(object):
def __init__(self, name=None, content=None):
self.name = name
self.content = content
def get_nodes(self):
c = []
c.append(self.name)
if self.content != []:
for a in self.content:
c.extend(a.get_nodes())
return c
>>> n = MyClass('me', [])
>>> m = MyClass('other', [n])
>>> m.get_nodes()
['other', 'me']
If your code doesn't work then you have to explain how your code is different from that.

Categories