Function as class attribute - python

I am writing a class where I would like to pass function as a class attribute and later use it, like that:
class Nevronska_mreza:
def __init__(self, st_vhodni, st_skriti, st_izhod, prenosna_funkcija=pf.sigmoid):
self.mreza = []
self.st_vhodni = st_vhodni
self.st_skriti = st_skriti
self.st_izhodni = st_izhod
self.prenosna_funckija = prenosna_funkcija
self.mreza.append([{'utezi': [random() for i in range(st_vhodni + 1)]} for j in range(st_skriti)])
self.mreza.append([{'utezi': [random() for i in range(st_skriti + 1)]} for j in range(st_izhod)])
def razsirjanje_naprej(self, vhod):
for sloj in self.mreza:
nov_vhod = []
for nevron in sloj:
nevron['izhod'] = self.prenosna_funkcija(self.aktivacijska_funkcija(nevron['utezi'], vhod))
nov_vhod.append(nevron['izhod'])
vhod = nov_vhod
return vhod
but it seems like this isn't the right way, I get the following error:
AttributeError: 'Nevronska_mreza' object has no attribute 'prenosna_funkcija'
Is it possible to do something like that?

Yes you can pass a function around as an argument however you have made a couple of mistakes.
Firstly you have used the word function, although not a reserved word it should be avoided as a name of an entity such as a variable.
Secordly you have used an optional parameter before mandatory parameters which will cause an error such as:
File "test.py", line 5
def __init__(self, function=fun1, data1, data2):
^
SyntaxError: non-default argument follows default argument
Thirdly when calling the method you have not specified the scope, the function name is in the self scope of the object.
Taking all of these into account the following is working code
def fun1(x):
return x+1
class A:
def __init__(self, data1, data2, fn=fun1):
self.fn = fn
self.data1 = data1
self.data2 = data2
def some_method(self):
y = self.fn(self.data1)
print(y)
b = A(1, 2, fun1)
b.some_method()
After posting your full code I can see that you currently have self.prenosna_funckija instead of prenosna_funkcija in the following line:
self.prenosna_funckija = prenosna_funkcija
This would explain the attribute error as when you are calling self.prenosna_funkcija it genuinely does not exist.

You're close:
def fun1(x):
return x+1
class A:
def __init__(self, function=fun1, data1=None, data2=None):
self.function = function
self.data1 = data1
self.data2 = data2
def some_method(self):
y = self.function(self.data1)
return y
a = A(data1 = 41)
result = a.some_method()
print(result)
prints
42

Related

My function works on its own but not callable from class

I've made a class as follow:
class Plugins:
def __init__(self):
pass
def voter_rep(self, loc, start_header, end_header):
self.loc = loc
ocr_xml = AbbyyXML(loc)
xml_doc = XMLDoc(ocr_xml, CONSTANTS)
xml_doc.split_words("", False)
self.start_header = start_header
self.end_header = end_header
header_pages = xml_doc.se_page(start_header, end_header)
## and stuff
voter_dict = {'Voter':[], 'Record_Key':[], 'Comments':[]}
## and stuff
return voter_dict, rep_dict
if I run the method function on its own and outside of the class it works totally fine, namely if I write the function as:
def voter_rep(loc, start_header, end_header):
ocr_xml = AbbyyXML(loc)
xml_doc = XMLDoc(ocr_xml, CONSTANTS)
xml_doc.split_words("", False)
header_pages = xml_doc.se_page(start_header, end_header)
## and stuff
voter_dict = {'Voter':[], 'Record_Key':[], 'Comments':[]}
## and stuff
return voter_dict, rep_dict
in the function alone I get rid of self and will just have voter_rep(loc, start_header, end_header) but when I want to call it from the class I do plugins.voter_rep(loc, start_header, end_header) which does not work, and it returns:
NameError: name 'plugins' is not defined
I wonder why is it that my function works on its own but not callable from the class?
You can do
plugins = Plugins()
loc = #some val
start_header = #some val
end_header = #some val
plugins.voter_rep(loc, start_header, end_header)
As the error message shows, you are using small 'p' instead of capital. Also since it is not a static function, so it is not good to call it via class name.
Plugins.voter_rep(loc, start_header, end_header)
Take note of the capital letter.

Object assignment and references question

Lets say i have the following code:
class asd:
def __init__(self):
self.var = "default"
def changeagain():
xa = asd()
xa.var = "changed"
return xa
def change(objct:asd):
newobjc = changeagain()
objct = newobjc
print(objct.var)
test = asd()
change(test)
print(test.var)
what i expect as output is:
changed
changed
nonetheless i get:
changed
default
What is the problem?
What i must do to get the desired output?
Here, you are changing the value of an object's instance variable and expecting the change to b reflected in another object. Whereas it is not possible in the case of instance variables of objects.
As per your need, I've changed certain statements in your program :
class asd:
var = "default"
def changeagain():
xa = asd()
asd.var = "changed"
return xa
def change(objct:asd):
newobjc = changeagain()
objct = newobjc
print(objct.var)
test = asd()
change(test)
print(test.var)
class asd:
def __init__(self):
self.var = "default"
def changeagain(asd):
# xa = asd()
asd.var = "changed"
return asd
def change(asd):
newobjc = changeagain(asd)
objct = newobjc
print(objct.var)
test = asd()
change(test)
print(test.var)
I have commented out the object creation in the changeagain() and passed the object of the class for which you want to change the value.
Earlier you were passing an object of the class but changing the value for a different object.
Happy coding

Initialise class without instantiate?

I'm trying to work on a simple class that fills in some lists and then tries to retrieve that information back, something like:
class Foo(object):
def __init__(self):
self.src = []
self.values = []
def addItems(self, name, val):
self.src.append(name)
self.values.append(val)
def getItem(self, item):
for i, x in enumerate(self.src):
if x == item:
return self.src[i], self.values[i]
To use this class, I first have to instanciate it, Foo(), and only then start adding and retrieving objects.
a = Foo()
a.addItems('A', '1')
a.addItems('B', '2')
a.src # ['A', 'B']
a.values # ['1', '2']
a.getItem('A') # ('A', '1')
Is there any way to add the elements without having to initialise the class first? Something like Foo.addItems('A', '1')(this gives a TypeError: addItems() missing 1 required positional argument: 'val').
I saw other related posts using #staticmethod, but couldn't figure out how to make it work in this example.
Not sure what exactly you have in mind. I guess you may get something close to what you have described. Two steps are needed.
First - create module, say, foo_module, where you create and instantiate your class:
class Foo:
def __init__(self):
self.src = []
self.values = []
def addItems(self, name, val):
self.src.append(name)
self.values.append(val)
def getItem(self, item):
for i, x in enumerate(self.src):
if x == item:
return self.src[i], self.values[i]
root_foo = Foo()
src = root_foo.src
values = root_foo.values
def addItems(*args):
return root_foo.addItems(*args)
def getItem(*args):
return root_foo.getItem(*args)
Second - import foo_module and use it:
import foo_module as f_m
f_m.addItems('A', '1')
f_m.addItems('B', '2')
print(f_m.getItem('A'))
print(f_m.src)
print(f_m.values)
Now you access the same Foo instance any time you access foo_module across all your scripts. By the way, it's how python logging module works (root logger).

Changing attributes from a method call

I'm trying to make a chopsticks game. Here's a wikipedia link to the game https://en.wikipedia.org/wiki/Chopsticks_(hand_game). So far I just added a couple methods so that one hand can attack another hand using the 'attack' method. I feel like the code I wrote is very verbose, ugly and maybe even wrong though. How can I write this more elegantly?
class game:
def __init__(self):
self.x_left = 1
self.x_right = 1
self.o_left = 1
self.o_right = 1
def set_x_left(self, num):
self.x_left = num
def set_x_right(self, num):
self.x_right = num
def set_o_left(self, num):
self.o_left = num
def set_o_right(self, num):
self.o_right = num
def dict_func(self, hand):
self.func= {'x_left': self.set_x_left, 'x_right': self.set_x_right,
'o_left': self.set_o_left, 'o_right': self.set_o_right}
return self.func[hand]
def dict_hand(self, hand):
self.hands = {'x_left': self.x_left, 'x_right': self.x_right,
'o_left': self.o_left, 'o_right': self.o_right}
return self.hands[hand]
def attack(self, from_hand, to_hand):
self.dict_func(to_hand)(self.dict_hand(from_hand) + self.dict_hand(to_hand))
your code seems to have some unnecessary methods. You can get rid of the methods that set the variables with a number:
def set_x_left(self, num):
self.x_left = num
When you create an instance of game you can use dot notation to set the values:
chopsticks = game()
# ^^^ that's the instance
chopsticks.set_x_left(0)
# is the same as
chopsticks.x_left = 0
As you can see it's quicker to type, doesn't require any methods. It's just attribute assignments. Doing this will affect you dict_func method, so you can create an anonymous function instead:
def dict_func(self, hand):
self.func = {'x_left': lambda self, x: self.x_left = x,
'x_right': lambda self, x: self.x_right = x,
'o_left': lambda self, x: self.o_left = x,
'o_right': lambda self, x: self.o_right = x}
return self.func[hand]
In fact you can declare the self.func self.hands attributes in __init__ to make sure that they're only assigned to once. Then in the function you can just write return self.func[hand]
Your dict_hand method is also slightly over complicated. Your aim is to get the attribute from the instance dict, so you can do:
def dict_hand(self, hand):
return getatttr(self, hand)
(You may want to rename this function :))

Error accessing class objects in python

I am having some problem accessing class instances. I am calling the class from a procedure, name of instance is defined in some variable. I want the instance name to be created of that value and then want to access it, but when i access it is giving error. Can some one please help to resolve this issue.
class myclass:
def __init__(self,object):
self.name = object
def mydef():
global a1
b = "a1"
b = myclass(b)
mydef()
print a1.name
Second Problem:
In my actual script, I have to create a large number of such instances from this function (around 100). So defining their name as global would be painful, is there a way i could access those instances outside function without having to declare them as global.
Modification:
class myclass:
def __init__(self,object,typename):
self.name = object
self.typeid = typename
def mydef():
file_han = open(file,"r")
while True:
line = file_han.readline()
if not line:
break
start = line.find('"')
end = line.find('"',start+1)
string_f = line[start+1:end]
myclass(string_f,'a11')
mydef(file)
print def.name
print def.typeid
File Contents are :
a11 "def"
a11 "ghi"
a11 "eff"
Here's how I'd do it. I don't know why you're messing around with globals, if you'd care to explain, I'll update my answer.
class Myclass(object):
def __init__(self, name):
self.name = name
def mydef():
return Myclass("a1")
a1 = mydef()
print a1.name
Gather your instances in a list:
instances = []
for x in range(1000):
instances.append(Myclass("Instance {0}".format(x)))
print instance[42].name
Note the changes:
Class names should be capitalized
Use object as the base class of your classes (since python 2.2, but no longer necessary in 3.x)
Don't shadow the built-in object with your parameter name
Just use the string "a1" directly as a parameter instead of assigning it to a variable
Return something from the function instead of passing the result by global variable
RE: Comment
You haven't said anything about the format of these files, so I'll just give an example where the file to be read contains one class name per line, and nothing else:
def mydef(filename):
ret = []
with open(filename) as f:
for line in f:
# Call `strip` on line to remove newline and surrounding whitespace
ret.append(Myclass(line.strip()))
return ret
So if you have several files and wish to add all your instances from all your files to a large list, do it like this:
instances = []
for filename in ["myfile1", "myfile2", "myfile3"]:
instances.extend(mydef(filename))
RE: OP Edit
def mydef(filename):
ret = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret.append(Myclass(string_f))
return ret
i = mydef("name_of_file")
RE: Comment
Oh, you want to access them by name. Then return a dict instead:
def mydef(filename):
ret = {}
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret[string_f] = Myclass(string_f)
return ret
i = mydef("name_of_file")
print i["ghi"].name # should print "ghi"
RE: Comment
If I understand you correctly, you want to have it both ways -- index by both line number and name. Well then why don't you return both a list and a dictionary?
def mydef(filename):
d = {}
L = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
instance = Myclass(string_f)
d[string_f] = instance
L.append(instance)
return L, d
L, d = mydef("name_of_file")
print d["ghi"].name
print L[3]
print L.index(d["ghi"])
You could use class as repository for your instances, for example
class Named(object):
def __init__(self,name):
self.name = name
def __new__(cls,name):
instance = super(type,cls).__new__(cls,name)
setattr(cls,name,instance)
return instance
def __repr__(self):
return 'Named[%s]'%self.name
Named('hello')
Named('x123')
Named('this is not valid attribute name, but also working')
print(Named.hello,Named.x123,getattr(Named,'this is not valid attribute name, but also working'))

Categories

Resources