Python (OOP) list append error - python

in need of a little insight. I have the following python code:
>>> class invader:
... def __init__(self):
// list
... self.parameters = []
...
... def parameters(self):
... param = self.parameters
... param.append('3')
...
>>> invade = invader()
>>> invade.parameters()
Running this in terminal produces the following error message:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not callable
How can I solve this?

You problem is using the same name for your attribute and method, rename self.parameters to self.param and use self.param in your method:
class invader:
def __init__(self):
self.param = []
def parameters(self):
self.param.append('3')
invade = invader()
invade.parameters()
print(invade.param)

In the last line:
invade.parameters()
You are effectively using the list parameters as a function. (Note () at the end)
Do a
print invade.parameters
will let you see the content of the list and remove the runtime error

Both your method and attribute contain the same name parameters so you can do as follows here:
def parameters(self):
self._parameters.append('3')
It's a common to encapsulate attributes with underscores, especially with methods of the same name.

Your method and attribute contain the same name parameters. Since data attributes will override method attributes with the same name. So invade.parameters is list, not function. You should rename your function, such as append_parameters.
If you want to call parameters function, you can try this way:invader.parameters(invade).But it's not recommended

Related

Python: Overload Instance Method and Class Method/ Access Instance Variable from Class Method

I was wondering what the best way to implement the following design would be in Python:
class Executor:
def __init__(self):
self.val = 5
def action(self):
self.action(self.val)
#classmethod
def action(cls, val):
print(f"Val is: {val}")
I want to be able to access the method both as an instance method that uses the value the object was initialised with, and as a class method which uses a passed in variable. Here is an example of the ways in which I would like to call it:
>>> Executor.action(3)
Val is: 3
>>> Executor().action()
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: action() missing 1 required positional argument: 'val'
I was thinking about trying to use keyword arguments, but I can't seem to get that to work either. Here is my code so far:
class Executor:
def __init__(self):
self.val = 5
#classmethod
def action(cls, val=None):
if val is None:
# This doesn't work; cls does not have attribute 'val'.
if hasattr(cls, "val"):
print(f"Val from instance: {cls.val}")
else:
raise ValueError("Called as class method and val not passed in.")
else:
print(f"Val passed in: {val}")
>>> Executor.action(3)
Val passed in: 3
>>> Executor().action()
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 13, in action
ValueError: Called as class method and val not passed in.
But the class instance does not have the val available for access.
The only other thing I can think of is using Hungarian notation, but it's not ideal as it's a bit messy, and it means there's multiple method names.
class Executor:
def __init__(self):
self.val = 5
def action_instance(self):
self.action_class(self.val)
#classmethod
def action_class(cls, val):
print(f"Val is: {val}")
>>> Executor.action_class(3)
Val is: 3
>>> Executor().action_instance()
Val is: 5
Any advice on a solid, clean approach would be greatly appreciated!
Cheers.
What you want to do looks strange to me, I am not sure you need that. Python cannot overload by method signatures/type, although there is the functools.singledispatch. So by defining action a second time you are actually replacing the first definition for the method.
The observable behaviour can be achieved with:
class Executor:
#classmethod
def action(cls, val=5):
return val
print(Executor().action())
print(Executor.action(3))
Outputs:
5
3
But again check first that you really need something like that, because it breaks one of the expectations of Python coders and Python data model: calling a method through the class is equivalent to calling the method through the instance given that you pass the instance to the class method.
obj = Executor()
obj.action() # this is the same as Executor.action(obj)

Import module functions as staticmethods into a class

I have a python module
helpers.py
def str_to_num(s: str):
'''Converts to int if possible else converts to float if possible
Returns back the string if not possible to convert to a number.
'''
# NOTE: These are not really funcs, but classes.
funcs = [int, float]
for func in funcs:
try:
res = func(s)
break
except ValueError:
continue
else:
res = s
return(res)
I have another module string_number.py
from helpers import str_to_num
class StringNumber:
def __init__(self, s):
self.s = s
str_to_num = str_to_num
#property
def value(self):
return(self.str_to_num(self.s))
def __repr__(self):
return(f'{self.__class__.__name__}({repr(self.s)})')
>>> from string_number import StringNumber
>>> sn = StringNumber(1)
>>> sn.value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "string_number.py", line 19, in value
return(self.str_to_num(self.s))
TypeError: str_to_num() takes 1 positional argument but 2 were given
However this works when accessing the function from the class:
>>> StringNumber.str_to_num(1)
1
Q.1: Why does the str_to_num attribute require two arguments when accessing it from the instance? Is self being passed to it? If so, why?
Now, I know I can add modify the __init__ method to make it an attribute of the instance
def __init__(self, s):
self.s = s
self.str_to_num = str_to_num
Further, I can resolve this by making a class of Helper functions and then inheriting from it.
from helpers import str_to_num
class Helper:
#staticmethod
def str_to_num(s):
return(str_to_num(s))
class StringNumber(Helper):
def __init__(self, s):
self.s = s
#property
def value(self):
return(self.str_to_num(self.s))
def __repr__(self):
return(f'{self.__class__.__name__}({repr(self.s)})')
Q: 2 Is there a way to make module functions, staticmethods of a class, without using inheritance? Or is this a really bad practice?
Q: 3 Assuming I had a helpers.py module, with a large amount of module functions. To incorporate them as staticmethods into my class, what would be the best way, without making a separate Helper class?
Q.1: Why does the str_to_num attribute require two arguments when accessing it from the instance? Is self being passed to it? If so, why?
You wrote "However this works when accessing the function from the class: StringNumber.str_to_num(1)". It works because you declared your method as a static method by defining it under your class definition.
As contrary to static method, instance method does pass the instance as a first argument when it's called. So when you called instance.str_to_num(1) your str_to_num(s: str) - no matter your type hinted it as a string - received instance as s argument and complained that value 1 hasn't got variable to hold it.

OOP attribute definition

I want to define an attribute in a method:
class variables:
def definition(self):
self.word = "apple"
Then I want to use the defined attribute:
test = variables()
print test.definition.word
Instead of writing 'apple' I get an error:
Traceback (most recent call last):
File "bezejmenný.py", line 6, in <module>
print test.definition.word
AttributeError: 'function' object has no attribute 'word'
definition is a method so you need to execute it
Because you are assigning a variable to self, you can access it through your instance as follows
test = variables()
test.definition()
print test.word
A few ideas:
It's best practice start class names with a capital letter
If you just want you class to have a field, you don't need your definition method
Extend your class with object because everything in python is objects (python 2.x only)
class Variables(object):
def __init__(self):
self.word = 'I am a word'
variables = Variables()
print variables.word
You can access instance attribute like this:
test = variable()
test.definition()
print test.word

Strange (for me) error in Python OOP

I'm a newbie and I'm having a really strange (like in the title, for me) problem.
This is the code:
from random import shuffle
class Carta:
listaSemi=[" ","Bastoni","Spade","Coppe","Denari"]
listaValori=[" ","Asso","Due","Tre","Quattro",
"Cinque","Sei","Sette","Otto","Nove","Dieci"]
def __init__(self,seme,valore):
self.seme=seme
self.valore=valore
def __str__(self):
s1=self.listaValori[self.valore]
s2=self.listaSemi[self.seme]
return " ".join((s1,"di",s2))
class Mazzo:
def __init__(self):
self.Carte=[]
def Crea(self):
for seme in range(1,5):
for valore in range(1,11):
self.Carte.append(Carta(seme, valore))
def Mescola(self):
shuffle(self.Carte)
When i do:
M=Mazzo
Mazzo.Crea(M)
I get:
Traceback (most recent call last):
File "<pyshell#62>", line 1, in <module>
Mazzo.Crea(M)
File "/home/administrator/Scrivania/Script/Carte.py", line 19, in Crea
self.Carte.append(Carta(seme, valore))
AttributeError: type object 'Mazzo' has no attribute 'Carte'
Thanks in advance for your help!
You are initilizing your class incorrectly. Try doing this:
m = Mazzo()
m.Crea()
So a quick explanation as to why. First of all, the first line initializes an object of type Mazzo and sets in to m (please note the '()' you need that for all methods, initialization or otherwise.) Since its only perimeter is self it can be left blank.
Next we want to call the Crea function, we do this by calling the object we just created and NOT the class itself.
You are assigning type to M instead of creating a new object. Probably you want to do this:
m=Mazzo()
m.Crea()
The problem is in how you are instantiating the class Mazzo
>>>M=Mazo
What is really assigned to M is the class object and not a Mazzo object:
>>>type(M)
<class 'type'>
Your next line is even more problematic:
>>> Mazzo.Crea(M)
That asks the Mazzo class to execute the Crea method, with a Mazzo class object as the argument. And Crea doesn't take any other arguments, let alone a class object. I suspect you may have some more reading to do about the self method argument in python.
The usual way of instantiating a new object of a given class is something like:
>>> class MyClass(object):
def __init__(self,someValue):
self.someValue = someValue
def aMethod(self)
print(self.someValue)
>>> newObject = MyClass(42)
>>> newObject.aMethod()
42
Good luck.
When you did
M=Mazzo
Mazzo.Crea(M)
What you did is Mazzo.Crea(Mazzo).
First off, M=Mazzo should be M=Mazzo(). When you call just plain Mazzo, it doesn't trigger __init__, although Mazzo() does.
FYI: calling Mazzo.Crea(Mazzo) will raise a TypeError, as in
TypeError: Crea takes exactly 1 argument (2 Given)

exec to add a function into a class

So I've looked at similar questions, and I've found some solutions to this, but I can't quite figure out how to do this.
What I'm trying to do is add a method to a class from a string. I can do this with the setattr() method, but that won't let me use self as an attribute in the extra method. Here's an example: (and I apologize for the variable names, I always use yolo when I'm mocking up an idea)
class what:
def __init__(self):
s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra'
exec(s)
setattr(self,"yolo",yolo)
what().yolo()
returns this:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: yolo() takes exactly 1 argument (0 given)
and if s = 'def yolo():\n\tself.extra = "Hello"\n\tprint self.extra'
then I get this result:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 2, in yolo
NameError: global name 'self' is not defined
This essentially means that I cannot dynamically create methods for classes, which I know is bad practice and unpythonic, because the methods would be unable to access the variables that the rest of the class has access to.
I appreciate any help.
You have to bind your function to the class instance to turn it into a method. It can be done by wrapping it in types.MethodType:
import types
class what:
def __init__(self):
s = 'def yolo(self):\n\tself.extra = "Hello"\n\tprint self.extra'
exec(s)
self.yolo = types.MethodType(yolo, self)
what().yolo()
On a side note, why do you even need exec in this case? You can just as well write
import types
class what:
def __init__(self):
def yolo(self):
self.extra = "Hello"
print self.extra
self.yolo = types.MethodType(yolo, self)
what().yolo()
Edit: for the sake of completeness, one might prefer a solution through the descriptor protocol:
class what:
def __init__(self):
def yolo(self):
self.extra = "Hello"
print self.extra
self.yolo = yolo.__get__(self)
what().yolo()
Another way, seems more elegant to me:
class what:
pass
ld = {}
exec("""
def yolo(self):
self.extra = "Hello"
print(self.extra)
""", None, ld)
# print('locals got: {}'.format(ld))
for name, value in ld.items():
setattr(what, name, value)
what().yolo()

Categories