AttributeError when monkey patching an object in python - python-3.x

I tried to monkey patch an object in Python.
class C:
def __init__(self):
self.__n = 0
def f(self):
self.__n += 1
def __str__(self):
return str(self.__n)
c = C()
def up(self):
self.__n += 2
import types
c.up = types.MethodType(up, c)
c.up()
But I got an AttributeError
Traceback (most recent call last):
File "untitled4.py", line 19, in <module>
c.up()
File "untitled4.py", line 15, in up
self.__n += 2
AttributeError: 'C' object has no attribute '__n'
How can I fix the error?

As your up function isn't declared inside a class, it is not possible to apply name mangling rules to its locals, while it is applied for the attribute name. Therefore you'd need to apply the name mangling manually in your function:
def up(self):
self._C__n += 2

Related

Super() class's attributes not inherited?

It seems the child class doesn't inherit the parent attributes, despite calling super().__init__(args).
I read
Python: subclass inherits super class attributes, but loses it's other attributes
and
Subclass is not inheriting the attributes of second Super Class
but I read the attributes should be inherited if called within super().__init__()
With the following code (3.10.1)
class interface(object):
MEDIA = ('COPPER','FIBER')
SPEED_COPPER = ('100', '1G', '2.5G', '5G', '10G')
SPEED_FIBER = ('10G', '25G', '40G', '100G')
TYPE_L2 = ('ACCESS', 'TRUNK', 'HYBRID')
def __init__(self, media = None, speed = None):
self.media = media
self.speed = speed
def set_media(self):
pass
def is_copper(self):
return self.media == 'COPPER'
def is_fiber(self):
return self.media == 'FIBER'
class copper_1G(interface):
def __init__(self):
super().__init__(media = 'COPPER', speed = '1G')
class generic_mod(object):
def __init__(self, max_slots):
self.slots = []
self.max_slots = max_slots
self.set_interfaces()
def set_interfaces(self):
if len(self.slots) < self.max_slots:
for slot in range(0,self.max_slots):
self.slots.append(copper_1G)
class module48_2(generic_mod):
MAX_SLOTS = 48
def __init__(self):
super().__init__(self.MAX_SLOTS)
self.set_interfaces()
>>> ff=module48_2()
>>> ff.slots[0].media
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'copper_1G' has no attribute 'media'
>>> ff.slots[0].speed
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'copper_1G' has no attribute 'speed'
the variable ff.slots[0] doesn't get the attributes media and speed of the parent class, though it gets the methods is_copper, is_fiber, etc etc...
class generic_mod(object):
...
def set_interfaces(self):
if len(self.slots) < self.max_slots:
for slot in range(0,self.max_slots):
self.slots.append(copper_1G)
self.slots.append(copper_1G) -> self.slots.append(copper_1G())

Getting unexpected NoneType error in Python

While trying to create a minimal, reproducible example for another problem in Python 3.7.3, I ran into a NoneType Error that I wasn't expecting.
Main program:
import worker
def multiply_worker_value(arguments):
current_Worker = arguments[0]
multiplier = arguments[1]
new_worker = current_Worker.change_value(multiplier)
return new_worker
current_worker = worker.Worker()
print("Printing value:")
print(current_worker.get_value()[0])
while(current_worker.get_value()[0] < 10):
paramList = [current_worker,2]
current_worker = multiply_worker_value(paramList)
print(current_worker.get_value()[0])
Worker class:
import numpy
class Worker():
def __init__(self):
self.values = numpy.random.rand(10)
def change_value(self,multiplier):
self.values = numpy.sum(self.values*multiplier)
def get_value(self):
return self.values
When this is run, I get:
Printing value:
0.10619190084595542
Traceback (most recent call last):
File "F:\Visual Studio\repos\Projects2020\tests\concurrent_test\concurrent_test\main.py", line 14, in <module>
while(current_worker.get_value()[0] < 10):
AttributeError: 'NoneType' object has no attribute 'get_value'
Press any key to continue . . .
and I am not sure why this is happening.
Inside the while loop, your current_worker gets overwritten with None:
current_worker = multiply_worker_value(paramList)
this calls:
new_worker = current_Worker.change_value(multiplier)
Your Worker.change_value method does not have a return statement, so it implicitly returns None.
Then, in the second iteration of your loop, your code tries to call get_value on None, which fails.

How to build a class-based decorator of a class in Python?

class Taggable:
TAG_ATTR_NAME = "_taggable_tag"
#staticmethod
def GetTag(target) -> str:
if not hasattr(target,Taggable.TAG_ATTR_NAME):
raise Exception(f"Object is not tagged")
return getattr(target,Taggable.TAG_ATTR_NAME)
def __init__(self, tag :str = "default_tag"):
self.tag = tag
def __call__(self,cls :type):
orig_new = cls.__new__
def my_new():
instance = orig_new(cls)
setattr(instance, Taggable.TAG_ATTR_NAME, self.tag)
return instance
if not isinstance(cls,type):
raise Exception(f"Decorator {type(self).__name__} applied to value {repr(cls)} of type {type(cls).__name__}")
cls.__new__ = my_new()
return cls
#Taggable
class A:
def __init__(self,fa :str):
self.fa = fa
print(f"__init__ called on A with fa={self.fa}, tagged as {Taggable.GetTag(self)}")
class B(A):
def __init__(self, fa: str, fb: str):
super().__init__(fa)
self.fb = fb
print(f"__init__ called on B with fb={self.fb}")
b: B = B("aaa","bbb")
print(Taggable.GetTag(b))
Running this on python 3.6 gives me the following error:
Traceback (most recent call last):
File "/Users/$user/Library/Preferences/PyCharmCE2019.1/scratches/scratch.py", line 35, in <module>
class B(A):
TypeError: __init__() takes from 1 to 2 positional arguments but 4 were given
Looking around the web there seems to be little to no authoritative documentation on how class decorator classes are initialized and called by the interpreter and what arguments are passed to their dunder methods

Using variables in __init__ method in Python

I have been given a Python module where I have a class named 'Node'. The __init__ method inside the class is given below:
def __init__(self, data = None, next = None):
self.fata = data
self._next = next
I want to know how this would differ if I simply mention data and next as variables and don't assign them to None? Like this:
def __init__(self, data, next):
self.fata = data
self._next = next
If
class A:
def __init__(self, data = None, next = None):
self._data = data
self._next = next
class B:
def __init__(self, data, next):
self._data = data
self._next = next
Then, e.g.:
>>> x = A(1,2)
>>> y = B(1,2)
>>> #no difference so far, but
>>> z = A()
>>> w = B()
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
w = B()
TypeError: __init__() missing 2 required positional arguments: 'data' and 'next'
Missing required arguments are a run-time error. They don't default to None.

Module Import from tkinter Widget

Not long ago I asked an question on how to import from an input statement. Nailed it. Now I'm upgrading my lengthy code to a GUI for the user. Same problem. How do I import a module based on user input from the tkinter widget Entry.
I originally had:
var1=__import__(input("Enter a module: "))
And attempted something like this:
import tkinter
var1=__import__(tkinter.Entry(top, bd=5)).pack()
A few different phrasings all resulted in the basic error:
TypeError: __import__() argument 1 must be str, not Entry
I have a few different methods still on my list to try. For example:
var1=Entry(top, bd=5).grid(row=7)
var2=Entry.get(var1)
var=__import__(var2)
This gives me the rather awful error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
return self.func(*args)
File "C:\Python33\Doc\Project\testing.py", line 21, in finish
var2=Entry.get(var1)
File "C:\Python33\lib\tkinter\__init__.py", line 2512, in get
return self.tk.call(self._w, 'get')
AttributeError: 'NoneType' object has no attribute 'tk'
You need Entry instance to work with it.
This way:
my_entry = Entry(top, bd=5) # you get object (Entry instance)
my_entry.grid(row=7) # you call object method grid()
entry_text = my_entry.get() # you call object method get()
var = __import__(entry_text)
BTW:
This way you get result of grid() function, not Entry instance.
var1 = Entry(top, bd=5).grid(row=7) # grid() returns always None
see
my_entry = Entry(top, bd=5)
grid_result = my_entry.grid(row=7) # grid() returns always None
var1 = grid_result
In this code you try to pack() imported library :)
var1 = __import__(tkinter.Entry(top, bd=5)).pack()
see
my_entry = Entry(top, bd=5) # you get object
imported_library = __import__(my_entry) # object can't be argument for __import__
var1 = imported_library.pack() # you can't pack library

Resources