Python object oriented implementation - python

Im trying this piece of code below but wondering why its not working..
Can you please let me know wht is the problem,
code.py
class Example():
def A1(self):
return self.B1() + self.B2()
def B1(self):
return 4 * self.C1()
def B2(self):
return 5
def C1(self):
return 2
def main():
spreadsheet = Example()
print spreadsheet.A1()
spreadsheet.C1 = 3
print spreadsheet.A1()

C1 starts out as a method - you call .A1(), which calls .B1(), which calls .C1(), which returns 2. So far, so good.
You then make .C1 a value (3) - you call .A1(), which calls .B1(), which tries to call .C1(), which blows up because the value 3 is not callable.
Maybe you want something like
class Spreadsheet(object):
def __getattribute__(self, cell):
val = object.__getattribute__(self, cell)
return val(self) if callable(val) else val
def main():
s = Spreadsheet()
s.a1 = lambda self: self.b1 + self.b2
s.b1 = lambda self: 4 * self.c1
s.b2 = 5
s.c1 = 2
print s.a1 # => 13
s.c1 = 3
print s.a1 # => 17

In your class, the variable C1 was just a variable that held an instance method. Setting it equal to 3 overrides the function.
For example:
def foo():
print 4
foo = 12 # foo is now the number 12, not a function
You did the same thing:
spreadsheet.C1 = 3
C1 was a function, but now it's a number. You can't call a number.

You mean that if you execute main you get a TypeError when it gets to print spreadsheet.A1()
It is because you overwrite the instance variable C1. It was assigned to a function, but then you reassign it to the integer 3. When it tries to process the instance method A1 it eventually tries to call self.C1() and finds an integer, which can't be called and shouldn't have the parenthesis after it, so it properly throws an error.
Depending on what you want to happen you have several options.
Accept that this is normal behavior and don't overwrite instance procedures.
Define a setter for C1 that would either return an error at that point or silently do nothing.

The name "C1" refers to a method (a callable object). But then you assign "C1" attribute to an integer (not callable), and clobber the method. Then when you call it with self.C1() it won't work anymore.

Related

unable to use attribute from a python function in another python script

I want to use one of the attributes returned by a function in a python script (x) into a python script (y)
The communication between both scripts works well; I can get functions and attributes, but doesn't allow me to attributes returned by a function.
Here is how I worked:
x.py
def func():
b = 10
a = 15
return [a,b]
c = 20
y.py
from x import func
import x
print (x.c)
print (func.b)
I get the "c" value and the following error AttributeError: 'function' object has no attribute 'b'
I have tried also to print x.b, and I've got AttributeError: module 'WorkingLSTM' has no attribute 'b'
Thanks in advance
The way to call func is by using func(), which would give you [a,b].
example:
funcResult = func()
a = funcResult[0]
b = funcResult[1]
funcResults is the return value from func(), that is the list [a,b].
That's not allowed, you have to call the function to get the value from the functions returned list.
a, b = func()
print(b)
# or just...
print(func()[1])
PS: It's "not allowed" because it doesn't make sense in any way; when there is no function call, there is not variable b at all. You might take a look at classes, they can hold static variables.
you cannot access local variables of a function.
these variables exist only during the the time where func is executed and are destroyed afterwards.
You can of course call the function and look at the result, but the result is just a list with two values
rslt = func()
print("A = ", rslt[0])
print("B = ", rslt[1])
The variable was declared inside a function making it a local variable and as such it can"t be accessed outside the function.
The variable is declared outside of the function making it a global variable and is not in anyway tied to your function.
The concept of attributes relates to Classes and you are dealing with a function so you might have to treat it as a class object.
If you are concerned bout accessing the local variables, you might as well do this:
y.py
from x import *
d = func() # func returns a list which is now
# identified/referenced by variable d
# displays the elements in the list using index position
print(d[0])
print(d[1])
If you want to use attributes, you may create a callable class instead of function:
class Func:
def __init__(self):
self.b = 10
self.a = 15
def __call__():
return [self.a, self.b]
func = Func()
Python has the concept of the scope. Local variables have no effect outside the function.
If you want to use it, use class and self or make getter function(but it's not Pythonic).
x.py
class X:
def __init__(self):
self.b = 10
self.a = 15
self.c = 20
def func(self):
return [self.a, self.b]
y.py
from x import X
x = X()
print(x.c)
print(x.func()[1])

C-like Static Variable inside a Python class method

After 20 years of C++ experience I am struggling to learn something of Python.
Now I'd like to have a method (a function inside a class) that has a "static" variable of its own, and not a static class variable.
Probably a pseudo code example can illustrate better what I want.
class dummy:
#staticmethod
def foo():
foo.counter += 1
print "You have called me {} times.".format(foo.counter)
foo.counter = 0
NOTE 1: I used #staticmethod just for simplicity, but this is irrelevant.
NOTE 2: This crashes with AttributeError: 'staticmethod' object has no attribute 'counter' but as I said above, this is a pseudo code to clarify my objective.
I have already learned that this works outside a class:
def foo():
foo.counter += 1
print "You have called me {} times.".format(foo.counter)
foo.counter = 0
But the same trick doesn't seem to work for member-functions.
Last minute information, I am restricted to using Python 2.7 (not my choice).
Is there any legal and reliable way to have a persistent variable (or constant) with scope restricted to the member-function scope?
Some relevant links
"What is the Python equivalent of static variables inside a function?":
https://stackoverflow.com/a/279586/466339
"There are no function-level static variables in Python":
https://code-maven.com/slides/python-programming/static-variable
Thanks in advance.
One way to achieve this is to tuck your variable away in a closure, so it will effectively be static for your purposes. Unfortunately, Python 2 does not support the nonlocal keyword, so we have to wrap our variable's value in an object (unless you only mean to reference and not mutate the variable (i.e. assign to the variable) in the method:
In [7]: class _Nonlocal:
...: def __init__(self, value):
...: self.counter = value
...:
...: def foo_maker():
...: nonlocal = _Nonlocal(0)
...: def foo(self):
...: nonlocal.counter += 1
...: print "You have called me {} times.".format(nonlocal.counter)
...: return foo
...:
In [8]: class Dummy(object): #you should always inherit from object explicitely in python 2
...: foo = foo_maker()
...:
In [9]: dummy = Dummy()
In [10]: dummy.foo()
You have called me 1 times.
In [11]: dummy.foo()
You have called me 2 times.
Of course, this is a lot of rigamarole simply to avoid using an instance variable. Perhaps the best solution is to make your method a custom object, and you can implement the descriptor protocol to make it callable as a method, and it will be usable as an instance method if you'd like:
In [35]: import types
...:
...: class Foo(object):
...: def __init__(this):
...: this.counter = 0
...: def __call__(this, self):
...: this.counter += 1
...: print "You have called me {} times.".format(this.counter)
...: print "here is some instance state, self.bar: {}".format(self.bar)
...: def __get__(this, obj, objtype=None):
...: "Simulate func_descr_get() in Objects/funcobject.c"
...: if obj is None:
...: return this
...: return types.MethodType(this, obj)
...:
In [36]: class Dummy(object): #you should always inherit from object explicitely in python 2
...: foo = Foo()
...: def __init__(self):
...: self.bar = 42
...:
In [37]: dummy = Dummy()
In [38]: dummy.foo()
You have called me 1 times.
here is some instance state, self.bar: 42
In [39]: dummy.bar = 99
In [40]: dummy.foo()
You have called me 2 times.
here is some instance state, self.bar: 99
All of this would be highly irregular and confusing to someone else who is used to python conventions, although I hope you see, the Python data-model offers a lot of power to customize things.
note, i've used this as the name of the first argument to avoid confusion with self that will actually come from the object that Foo get's bound to as a method.
Again, I should reiterate, I would never do this. I would just use an instance variable, or perhaps a generator if your function needs to maintain state, and could be used as an iterator.
No, there is not. You've already found the Python version: a class variable that you, the supreme overlord of class dummy development, will access only within function foo.
If it would help to know the rationale for this, you can start that path here. I expect that you've already been through much of this; however, this answer gives Python specifics for more Pythonic ways to implement what you need.
As #Prune already mentioned there is no real way of doing so.
However, if you want the static variable inside a method to be available only to the object it belongs to (as it is in C++ as far as I remember), you should define it in the constructor or as a class variable with a non-static method:
from __future__ import print_function
class dummy:
def __init__(self, counter=0):
self._foo_counter = 0
def foo(self):
self._foo_counter += 1
print("You have called me {} times.".format(self._foo_counter))
or:
class dummy:
def foo(self):
self._foo_counter += 1
print("You have called me {} times.".format(self._foo_counter))
_foo_counter = 0
This way, running:
x = dummy()
for _ in range(4):
x.foo()
y = dummy()
for _ in range(4):
y.foo()
Results in:
You have called me 1 times.
You have called me 2 times.
You have called me 3 times.
You have called me 4 times.
You have called me 1 times.
You have called me 2 times.
You have called me 3 times.
You have called me 4 times.
Note that the two versions do not behave in exactly the same way.
When you define _foo_counter in the class directly, you will have access to the _foo_counter variable both for the object (self._foo_counter) and for the class itself (dummy._foo_counter).
The dummy._foo_counter will be static for every use of the class and will persist across multiple instances of the class, so across multiple objects.
This is also the only variable that you can access if you use the #staticmethod decorator on dummy.foo():
class dummy:
#staticmethod
def foo():
dummy._foo_counter += 1
print("You have called me {} times.".format(dummy._foo_counter))
_foo_counter = 0
Here, self or _foo_counter will not be accessible, and your only option is to use the class-wide variable dummy._foo_counter (which, as already mentioned, you could use with methods not decorated with #staticmethod as well).
So that running again:
x = dummy()
for _ in range(4):
x.foo()
y = dummy()
for _ in range(4):
y.foo()
results in:
You have called me 1 times.
You have called me 2 times.
You have called me 3 times.
You have called me 4 times.
You have called me 5 times.
You have called me 6 times.
You have called me 7 times.
You have called me 8 times.
Using a mutable type as the default value for a keyword argument for your function is maybe the simplest approach:
class Dummy:
#staticmethod
def foo(_counter=[0]): # here using a list, but you could use a dictionary, or a deque
_counter[0] += 1
print "You have called me {} times.".format(_counter[0])
The rationale is that this variable is initialized only once; its latest value remains in the closure formed.
I already posted this in an old post, but nobody noticed it
As I have a different idiomatic objective with static variables, I would like to expose the following:
In a function, I want to initialize a variable only once with a calculated value which may be a bit costly.
As I love nice-writing, and being an old C-style programmer. I tried to define a macro-like writing:
def Foo () :
StaticVar( Foo, ‘Var’, CalculateStatic())
StaticVar( Foo, ‘Step’, CalculateStep())
Foo.Var += Foo.Step
print(‘Value of Var : ‘, Foo.Var)
Then, I wrote ‘StaticVar’ like this:
def StaticVar(Cls, Var, StaticVal) :
if not hasattr(Cls, Var) :
setattr(Cls, Var, StaticVal)
I can even write nicer code in Python:
def StaticVars(Cls, **Vars) :
for Var, StaticVal in Vars.items() :
if not hasattr(Cls, Var) :
setattr(Cls, Var, StaticVal)
def Foo () :
StaticVars( Foo, Var = CalculateStatic(),Step= CalculateStep()))
Foo.Var += Foo. Step
print(‘Value of Var : ‘, Foo.Var)
Sure, this is a nice way to write the code, but my objective (only one call of initialization functions) is not met (just add a print in the initialization function to see that the it is called often) ! The fact is that, in a function call, the parameter value is evaluated even before the function is called.
def CalculateStatic() :
print("Costly Initialization")
return 0
def CalculateStep() :
return 2
def Test() :
Foo()
Foo()
Foo()
>>> Test()
Costly Initialization
Value of Var : 2
Costly Initialization
Value of Var : 4
Costly Initialization
Value of Var : 6
To meet my objective, I’d rather write something like this:
def Foo () :
if not hasattr(Foo, ‘Var’) :
setattr ( Foo, ‘Var’, CalculateStatic())
setattr ( Foo, ‘Step’, CalculateStep())
Foo.Var += Foo. Step
print(‘Value of Var : ‘, Foo.Var)
>>> Test()
Costly Initialization
Value of Var : 2
Value of Var : 4
Value of Var : 6
And it could be “nicely written” like this (I used the underscore notation refering to “private == static”):
def StaticVars(Cls, **Vars) :
for Var, StaticVal in Vars.items() :
setattr(Cls, Var, StaticVal)
def Foo () :
_ = Foo
try :
__ = _.Var
except AttributeError : # The above code could only generate AttributeError Exception
# the following code is executed only once
StaticDefVars(_, Var= CalculateStatic(), Step = CalculateStep())
_.Var += _. Step
print(‘Value of Var : ‘, Foo.Var)
Attention must be paid to not put 'calculation code' in the 'try' clause which could generate extra 'AttributeError' exception.
Sure, if Python had had 'Marcro preprocessing', it would be even nicer
"'

python object as argument of a function

I know that python pass object by reference, but why the second output of codes below is 3 other than 10?
class a():
def __init__(self, value):
self.value = value
def test(b):
b = a(10)
b = a(3)
print(b.value)
test(b)
print(b.value)
Python objects are passed by value, where the value is a reference. The line b = a(3) creates a new object and puts the label b on it. b is not the object, it's just a label which happens to be on the object. When you call test(b), you copy the label b and pass it into the function, making the function's local b (which shadows the global b) also a label on the same object. The two b labels are not tied to each other in any way - they simply happen to both be currently on the same object. So the line b = a(10) inside the function simply creates a new object and places the local b label onto it, leaving the global b exactly as it was.
You did not return a value from the function to put into the class. This means the 'b' is irrelevant and does nothing. The only connection is the name 'b'
You need to reassign the value 'b' to be able to call the class.
class a():
def __init__(self, value):
self.value = value
def test(b):
b = a(10)
return b
b = a(3)
print(b.value)
b = test(3)
print(b.value)

List of objects function not working

Sorry for the title, I hope it reflects correctly my problem :
In the following code, I was expecting the result to be result 0 1 2 but instead I have 2 2 2. The code inside my_function seems to be interpreted with the last instance of obj. What is wrong ?
class Example:
def __init__(self, x):
self.x = x
def get(self):
return self.x
a_list = []
for index in range(3):
obj = Example(index)
def my_function(x):
#some stuff with x like obj.another_function(x)
return obj.get()
a_list.append(my_function)
for c in a_list:
print(c())
When you define this
def my_function():
return obj.get()
Python will understand that my_function should run the get() method of an object called obj and return the value. It won't know the value of obj and what the get() method does until you attempt to call it.
So, you are actually defining three different functions that will eventually do the same thing. And, in the end, running the same code thrice.
But why is the return 2 2 2?
Because after the last iteration, the value of obj is Example(2)* because you redefine its value at every iteration, and the last one remains.
*
because of this line obj = Example(index)
Understanding a few things about how python works will help you understand what's happening here. Here obj is a closure, closures are evaluated at call time, not when the function is defined so if I do this:
x = "hello"
def printX():
print x
x = "goodbye"
printX() # goodbye
I get "goodbye" because printX is referencing a global variable in my module, which changes after I create printX.
What you want to do is create a function with a closure that references a specific object. The functional way to do this is to create a function that returns another function:
x = "hello"
def makePrintX(a):
def printX():
# We print a, the object passed to `makePrintX`
print a
return printX
# x is evaluated here when it is still "hello"
myPrintX = makePrintX(x)
x = "goodbye"
myPrintX() # "hello"
If you're having trouble understanding the above example I would recommend reading up on python's scoping rules. For your example, you could do something like this:
class Example:
def __init__(self, x):
self.x = x
def get(self):
return self.x
def makeObjFunction(obj):
def objFunction(x):
return obj.get()
return objFunction
a_list = []
for index in range(3):
obj = Example(index)
my_function = makeObjFunction(obj)
a_list.append(my_function)
for c in a_list:
print(c("some value"))
You are appending three my_functions to the a_list which are all closures over the same Example object. Try:
def my_function():
return obj
<__main__.Example object at 0x0054EDF0>
<__main__.Example object at 0x0054EDF0>
<__main__.Example object at 0x0054EDF0>
You can see they have the same id so calling get() on each should give the same answer.
If you just append the obj.get function (and drop the my_function) it'll work fine.
a_list.append(obj.get)
....
0
1
2
Edit: You've updated your question so to let you do more stuff in my_function(). It's still basically a scoping problem.
def my_func_factory(p_obj):
def my_function(x):
#some stuff with x like obj.another_function(x)
return p_obj.get()
return my_function
for index in range(3):
obj = Example(index)
a_list.append(my_func_factory(obj))
Since my_function can't see obj being reassigned, each instance doesn't pick up the change.
I think append() during the for just append the function address in a_list[]. After for iteration, the a_list is really given the number. Then it discovers the address of my_function, and they get the number in my_function, this is, 2. That's why you get [2,2,2].
Or maybe, in my_function, function give the method of "obj". But for iteration change the "obj" memory address each time, so the symbol "obj" always aim to the newest object Example. Due to my_function always get "obj", you get the same number from the last object.

Is it possible to make Python functions behave like instances?

I understand that functions can have attributes. So I can do the following:
def myfunc():
myfunc.attribute += 1
print(myfunc.attribute)
myfunc.attribute = 1
Is it possible by any means to make such a function behave as if it were an instance? For example, I'd like to be able to do something like this:
x = clever_wrapper(myfunc)
y = clever_wrapper(myfunc)
x.attribute = 5
y.attribute = 9
x() # I want this to print 6 (from the 5 plus increment)
y() # I want this to print 10 (from the 9 plus increment)
As it stands, there is only one "instance" of the function, so attribute only exists once. Modifying it by either x or y changes the same value. I'd like each of them to have their own attribute. Is that possible to do at all? If so, can you provide a simple, functional example?
It is important that I be able to access attribute from inside of the function but have the value of attribute be different depending on which "instance" of the function is called. Essentially, I'd like to use attribute as if it were another parameter to the function (so that it could change the behavior of the function) but not pass it in. (Suppose that the signature of the function were fixed so that I cannot change the parameter list.) But I need to be able to set the different values for attribute and then call the functions in sequence. I hope that makes sense.
The main answers seem to be saying to do something like this:
class wrapper(object):
def __init__(self, target):
self.target = target
def __call__(self, *args, **kwargs):
return self.target(*args, **kwargs)
def test(a):
return a + test.attribute
x = wrapper(test)
y = wrapper(test)
x.attribute = 2
y.attribute = 3
print(x.attribute)
print(y.attribute)
print(x(3))
print(y(7))
But that doesn't work. Maybe I've done it incorrectly, but it says that test does not have attribute. (I'm assuming that it's because wrapper actually has the attribute.)
The reason I need this is because I have a library that expects a function with a particular signature. It's possible to put those functions into a pipeline of sorts so that they're called in order. I'd like to pass it multiple versions of the same function but change their behavior based on an attribute's value. So I'd like to be able to add x and y to the pipeline, as opposed to having to implement a test1 function and a test2 function that both do almost exactly the same thing (except for the value of the attribute).
You can make a class with a __call__ method which would achieve a similar thing.
Edit for clarity: Instead of making myfunc a function, make it a callable class. It walks like a function and it quacks like a function, but it can have members like a class.
A nicer way:
def funfactory( attribute ):
def func( *args, **kwargs ):
# stuff
print( attribute )
# more stuff
return func
x = funfactory( 1 )
y = funfactory( 2 )
x( ) # 1
y( ) # 2
This works because the functions are closures, so they will grab all local variables in their scope; this causes a copy of attribute to be passed around with the function.
class Callable(object):
def __init__(self, x):
self.x = x
def __call__(self):
self.x += 1
print self.x
>> c1 = Callable(5)
>> c2 = Callable(20)
>> c1()
6
>> c1()
7
>> c2()
21
>> c2()
22
A generator might be an alternate solution here:
def incgen(init):
while True:
init += 1
print init
yield
x = incgen(5)
y = incgen(9)
x.next() # prints 6
y.next() # prints 10
y.next() # prints 11
x.next() # prints 7
You can't dig back in to the generator and manipulate the data though.
#!/usr/bin/env python
# encoding: utf-8
class Callable(object):
attribute = 0
def __call__(self, *args, **kwargs):
return self.attribute
def main():
c = Callable()
c.attribute += 1
print c()
if __name__ == '__main__':
main()

Categories

Resources