Overwrite method at runtime in python - python

I have method that run many times. I dont want to nest ifs inside but rather want to overwrite method and then run it. I know that i can overwrite class method by simple assigment, but overwriten method doesn't see private members:
class X:
def __init__(self, a):
self.a = a
self.__b = a
def m(self):
print self.a
print self.__b
def a2(self):
print (2*self.a)
print (2*self.__b)
x = X(2)
x.m()
X.m = a2
x.m()
output:
2
2
4
Traceback (most recent call last):
File "t.py", line 17, in <module>
x.m()
File "t.py", line 12, in a2
print (2*self.__b)
AttributeError: X instance has no attribute '__b'
Is there any chance to solve this problem? Google doesn't show answer :(

Attributes within classes that start with double underscores are name-mangled. Never use them unless you're certain you need them. There's nothing private about them, so you should use a single underscore instead.
The reason you're having this problem is because the attribute access in a2() is not name-mangled.

Related

Is there a way to define a variable that is a parameter inside a function in Python?

Is it possible to define a variable that is a parameter inside a function?
I've tried doing this:
def myfunc(variable):
variable = 5
myfunc(x)
print(x)
I was expecting to see the number "5" printed on my screen, because I'm defining x (which is 5) and then printing it.
But I get this NameError:
Traceback (most recent call last):
File "C:\Users\yoelc\PycharmProjects\Test\app.py", line 4, in <module>
myfunc(x)
NameError: name 'x' is not defined
I know it is possible to do this:
def myfunc():
return 5
x = myfunc()
print(x)
But that's not what I'm trying to do.
Is there a way to define this?
Maybe not exactly what you want but pretty similar:
def myfunc(variable):
globals()[variable] = 5
myfunc('x')
print(x)
That being said this is a bad idea, unless you really need to use metaprogramming for some reason

Why `__iter__` does not work when defined as an instance variable?

If I define the __iter__ method as follows, it won't work:
class A:
def __init__(self):
self.__iter__ = lambda: iter('text')
for i in A().__iter__():
print(i)
iter(A())
Result:
t
e
x
t
Traceback (most recent call last):
File "...\mytest.py", line 10, in <module>
iter(A())
TypeError: 'A' object is not iterable
As you can see, calling A().__iter__() works, but A() is not iterable.
However if I define __iter__ for the class, then it will work:
class A:
def __init__(self):
self.__class__.__iter__ = staticmethod(lambda: iter('text'))
# or:
# self.__class__.__iter__ = lambda s: iter('text')
for i in A():
print(i)
iter(A())
# will print:
# t
# e
# x
# t
Does anyone know why python has been designed like this? i.e. why __iter__ as instance variable does not work? Don't you find it unintuitive?
It is done by design. You can find the thorough description here: https://docs.python.org/3/reference/datamodel.html#special-method-lookup
Short answer: the special method must be set on the class object itself in order to be consistently invoked by the interpreter.
Long answer: the idea behind this is to speed up well-known constructions. In your example:
class A:
def __init__(self):
self.__iter__ = lambda: iter('text')
How often are you going to write a code like this in real life? So, what Python does - it skips a dictionary lookup of the instance, i.e. iter(A()) simply does not "see" that self.__iter__, which is actually self.__dict__['__iter__'] in this case.
It also skips all the __getattribute__ instance and metaclass lookup gaining a significant speedup.

'int' object has no attribute when calling recursive function in python

Not sure what is wrong with the Python code below. Will appreciate any help. I have looked into here and here, but could not solve my issue.
Code:
class myClass:
def factorial(n,self):
if n == 1:
return 1
else:
return n * self.factorial(n-1)
obj = myClass()
obj.factorial(3)
Error
Traceback (most recent call last):
File "a.py", line 9, in <module>
obj.factorial(3)
File "a.py", line 6, in factorial
return n * self.factorial(n-1)
AttributeError: 'int' object has no attribute 'factorial'
You transposed the parameter names for factorial. The one that refers to the object itself must come first. As it is, you're trying to access the factorial variable of the number that was passed in. Change your definition of factorial to this:
def factorial(self, n):
...
self needs to be the first argument to a class function. Change
def factorial(n,self)
to
def factorial(self, n)
change your method signature to
def factorial(self, n)
instead of
def factorial(n, self)
because when you call a class method via object. python expects reference to the class object as a first parameter. in your case it's 'int'. which is not reference to the class object.

notation for accessing class and object attributes in python

In the following code ;
>>> class fooo():
def __init__(self):
self.a=[]
>>> fooo().a
[]
>>> fooo.a
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
fooo.a
AttributeError: class fooo has no attribute 'a'
i'm a little confuse about the notations fooo().a and fooo.a for accessing the variable "a".Is it that whenever we use fooo().a a object of fooo() class is thrown and it is equivalent to doing as:
>>> m=fooo()
>>> m.a
[]
; while using the notation fooo.a , we are expecting a to be a class/static variable ? Is i'm right or it is something else?
a is an instance attribute. It can be accessed using fooo().a. But note that doing that just throws away the fooo instance created; a more sensible example is:
y = fooo()
y.a = 5
It doesn't exist until an instance of the class is created. Yeah you are totally correct.

Two-parter: Why doesn't this code call the function I want, and can I do this without making a separate function for it?

This is a part of a larger program, what's supposed to happen is the Score.print_points() line calls the print_points() function in class Score, then print the self.points variable.
class Score(object):
def __init__(self, points):
self.points = points
def set_score(self):
self.points = 100
# This is going to be used for something else
def change_score(self, amount):
self.points += amount
def print_points(self):
print self.points
Score.print_points()
When I run it, though, I get this error:
Traceback (most recent call last):
File "sandbox.py", line 15, in <module>
Score.print_points()
TypeError: unbound method print_points() must be called with Score instance as first argument (got nothing instead)
I'm really unfamiliar with lingo, but I thought that I was calling with the Score instance as my first argument?
As for the second part: Is there a way of making printing self.points without making a separate function within the Score class to do so?
The problem is you're calling print_points on the class itself, not an instance of that class.
Try
>>> score = Score(0)
>>> score.print_points()
0
For your second question:
As for the second part: Is there a way of making printing self.points without making a separate function within the Score class to do so?
You could just do
>>> print score.points

Categories