This question already has answers here:
Inner class function without self
(5 answers)
Closed 2 years ago.
I was reading about instance, static, and class methods, and found the following.
This:
class A:
def a(self, num):
print("A.a(): ", num)
#staticmethod
def aa(num):
print("A.aa(): ", num)
works exactly as expected:
>>> A.a(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a() missing 1 required positional argument: 'num'
# I understand that this happens since `a()` is an instance method
>>> A.aa(1)
A.aa(): 1
>>> A().a(1)
A.a(): 1
However, if I modify A.a() to remove self from its parameters, i.e.:
class A:
def a(num):
print("A.a(): ", num)
#staticmethod
def aa(num):
print("A.aa(): ", num)
this happens:
>>> A.a(1)
A.a(): 1
# I don't understand why this works
>>> A.aa(1)
A.aa(): 1
>>> A().a(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a() takes 1 positional argument but 2 were given
# I understand that this happens because the first argument
# being given to `a()` is the instance of A
What exactly happened here? If I don't pass self to the a() method, what kind of a method is it? Why does it work without an instance of the class?
This is a static method. It will work, but it will not be able to access any of the other properties/methods that the class has. For example, suppose you have the following class.
class newClass:
b = 9
def print_b():
print(b)
newClass.print_b()
This will throw an error, since the function can not access the variable b. Hope this helps.
Similarly, you can not do the following, because when you call a method like this, you automatically pass an instance of the class into the function. Consequently, the function will throw an error saying it expects 0 positional arguments, but you have passed one.
x = newClass()
x.print_b()
Related
Let us, counterfactually, assume I had a good reason for wanting to make builtin print a static method of some class.
My, apparently wrong, gut feeling was that I need to declare it static doing something like
class sm:
p = staticmethod(print)
as opposed to
class no_sm:
p = print
But it seems both work just fine.
a = sm()
b = no_sm()
a.p("hello")
b.p("hello")
prints
hello
hello
Why does it just work and is there any difference between the two?
Related: Why use staticmethod instead of no decorator at all
for ~most normal functions, they go through a descriptor protocol (__get__) and so they need special decorating when attached to classes in the way you're doing.
take for example:
def f():
print('hi')
class C:
f = f
class D:
f = staticmethod(f)
in this case C().f() errors:
>>> C().f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional arguments but 1 was given
that's because it goes through:
>>> C.f.__get__(C())()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional arguments but 1 was given
but you'll notice, that print has no such attribute __get__:
>>> hasattr(print, '__get__')
it even has a different type!
>>> type(print)
<class 'builtin_function_or_method'>
>>> type(f)
<class 'function'>
so the answer is: print (along with other C functions) without special treatment do not participate in the method descriptor protocol so they act as normal callable objects without attachment of self
This question already has answers here:
"TypeError: method() takes 1 positional argument but 2 were given" but I only passed one
(10 answers)
Closed 2 years ago.
So I am new to class in Python but not new to classes in general.
I want to generate a new number in the object I create, and constantly change it.
So I did
class ArmedBandit1:
num = 0
def spin():
num = random(10)
a1 = ArmedBandit1()
a1.spin()
print(a1.num)
Now I get an error
Traceback (most recent call last):
File "main.py", line 9, in <module>
a1.spin()
TypeError: spin() takes 0 positional arguments but 1 was given
But I didn't give it any arguments, and if I try to remove the "()" it ignores the method.
Define with self as first parameter! Define init and assign property! (To get random number in a range use random.randrange(10))
import random
class ArmedBandit1:
def __init__(self):
self.num = 0
def spin(self):
self.num = random.randrange(10)
a1 = ArmedBandit1()
a1.spin()
print(a1.num)
basics of python classes
As #Mike67 suggested in the comments, you need to include the parameter self to have the method work for a particular instance of the class.
In order for the object to assign a variable to it, you must create a init() function. You must also use the self keyword to refer to the object that you're creating. Here's an example with your code:
import random
class ArmedBandit1:
def __init__(self):
self.num = 0
def spin(self):
self.num = random.randrange(10)
a1 = ArmedBandit1()
a1.spin()
print(a1.num)
Fixed Code!
import random
class ArmedBandit1:
def spin(self):
return random.randrange(10)
a1 = ArmedBandit1()
print(a1.spin())
Thank you to the help above!!
This question already has answers here:
Don't understand this TypeError: 'list' object is not callable
(2 answers)
Closed 4 years ago.
I have a class Match:
class Match(object):
def __init__(self,id):
self.id = id
def result(self):
# somehow find the game result
self.result = result
return self.result
If I initialize a match object as
m = Match(1)
when I call the method result I get
m.result
Out[18]: <bound method Match.result of <football_uk.Match object at 0x000000000B0081D0>>
When I call it with the parenthesis, I get
m.result()
Out[19]: u'2-3'
That is the correct answer. However, when I try to call a second, third, fourth, etc. time the method, I get
m.result()
Traceback (most recent call last):
File "<ipython-input-20-42f6486e36a5>", line 1, in <module>
m.result()
TypeError: 'unicode' object is not callable
If instead now I call the method without the parenthesis, it works:
m.result
Out[21]: u'2-3'
The same with other similar methods.
You have given your instance an attribute named result:
self.result = result
This now masks the method. You can't use the same name as the method if you don't want it masked. Rename the attribute or the method.
You could use the name _result for example:
def result(self):
# somehow find the game result
self._result = result
return self._result
self is just another reference to the same object that m references. Attributes set or found on self are the same ones that you can find on m, because they are the same object. There is no difference between m.result and self.result here.
This question already has answers here:
TypeError: attack() missing 1 required positional argument: 'self'
(2 answers)
Closed 4 years ago.
I'm new to Python. I've written two Classes, the second one has an instance of the first one as a member variable. Now I want to call a method of Class2 via the instance of it in class one. I could not find an answer for it. Something like this:
class Class1:
def uselessmethod(self):
pass
class Class2:
def __init__(self):
self.c = Class1()
def call_uselessmethod(self):
self.c.uselessmethod()
k = Class2
k.call_uselessmethod() # Error!
Gives the following error:
k.call_uselessmethod() #Error
TypeError: call_uselessmethod() missing 1 required positional argument: 'self'
Any idea of what is going on here? Thanks in advance.
call_uselessmethod requires that there first be an instance of Class2 before you use it. However, by doing this:
k = Class2
you are not assigning k to an instance of Class2 but rather Class2 itself.
To create an instance of Class2, add () after the class name:
k = Class2()
k.call_uselessmethod()
Now, your code will work because k points to an instance of Class2 like it should.
To create the instance, you need to call the class, k = Class2().
What was really happening the that k = Class2 created an alias to the class and k.call_uselessmethod`` created an unbound method which requires that you pass in the instance as the argument.
Here is a session that explains exactly what is happening:
>>> k = Class2 # create an alias the Class2
>>> k == Class2 # verify that *k* and *Class2* are the same
True
>>> k.call_uselessmethod # create an unbound method
<unbound method Class2.call_uselessmethod>
>>> k.call_uselessmethod() # call the unbound method with the wrong arguments
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
k.call_uselessmethod() # call the unbound method with the wrong arguments
TypeError: unbound method call_uselessmethod() must be called with Class2 instance as first argument (got nothing instead)
Note, the error message in Python2.7.6 has been improved over what you were seeing :-)
The statement:
k = Class2
Is actually assigning the variable k to the class itself, which is a type object. Remember, in Python everything is an object: classes are simply type objects.
>>> class Class2: pass
...
>>> k = Class2
>>> type(k)
>>> <class 'type'>
What you want is an instance of Class2. For that you must call Class2's constructor:
k = Class2()
It's not a real world program but I would like to know why it can't be done.
I was thinking about numpy.r_ object and tried to do something similar but just making a class and not instantiating it.
a simple code (has some flaws) for integers could be:
class r_:
#classmethod
def __getitem__(clc, sl):
try:
return range(sl)
except TypeError:
sl = sl.start, sl.stop, sl.step
return range(*(i for i in sl if i is not None))
but as I try to do r_[1:10] i receive TypeError: 'type' object is not subscriptable.
Of course the code works with r_.__getitem__(slice(1,10)) but that's not what I want.
Is there something I can do in this case instead of using r_()[1:10]?
The protocol for resolving obj[index] is to look for a __getitem__ method in the type of obj, not to directly look up a method on obj (which would normally fall back to looking up a method on the type if obj didn't have an instance attribute with the name __getitem__).
This can be easily verified.
>>> class Foo(object):
pass
>>> def __getitem__(self, index):
return index
>>> f = Foo()
>>> f.__getitem__ = __getitem__
>>> f[3]
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
f[3]
TypeError: 'Foo' object does not support indexing
>>> Foo.__getitem__ = __getitem__
>>> f[3]
3
I don't know why exactly it works this way, but I would guess that at least part of the reason is exactly to prevent what you're trying to do; it would be surprising if every class that defined __getitem__ so that its instances were indexable accidentally gained the ability to be indexed itself. In the overwhelming majority of cases, code that tries to index a class will be a bug, so if the __getitem__ method happened to be able to return something, it would be bad if that didn't get caught.
Why don't you just call the class something else, and bind an instance of it to the name r_? Then you'd be able to do r_[1:10].
What you are trying to do is like list[1:5] or set[1:5] =) The special __getitem__ method only works on instances.
What one would normally do is just create a single ("singleton") instance of the class:
class r_class(object):
...
r_ = r_class()
Now you can do:
r_[1:5]
You can also use metaclasses, but that may be more than is necessary.
"No, my question was about getitem in the class, not in the instance"
Then you do need metaclasses.
class r_meta(type):
def __getitem__(cls, key):
return range(key)
class r_(object, metaclass=r_meta):
pass
Demo:
>>> r_[5]
range(0, 5)
If you pass in r_[1:5] you will get a slice object. Do help(slice) for more info; you can access values like key.stop if isinstance(key,slice) else key.
Define __getitem__() as a normal method in r_'s metaclass.
The reason for this behavior lies in the way how special methods like __getitem__() are lookup up.
Attributes are looked up first in the objects __dict__, and, if not found there, in the class __dict__. That's why e.g. this works:
>>> class Test1(object):
... x = 'hello'
...
>>> t = Test1()
>>> t.__dict__
{}
>>> t.x
'hello'
Methods that are defined in the class body are stored in the class __dict__:
>>> class Test2(object):
... def foo(self):
... print 'hello'
...
>>> t = Test2()
>>> t.foo()
hello
>>> Test2.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Test2 instance as first argument (got nothing
instead)
So far there's nothing surprising here. When it comes to special methods however, Python's behavior is a little (or very) different:
>>> class Test3(object):
... def __getitem__(self, key):
... return 1
...
>>> t = Test3()
>>> t.__getitem__('a key')
1
>>> Test3['a key']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'type' object is unsubscriptable
The error messages are very different. With Test2, Python complains about an unbound method call, whereas with Test3 it complains about the unsubscriptability.
If you try to invoke a special method - by way of using it's associated operator - on an object, Python doesn't try to find it in the objects __dict__ but goes straight to the __dict__ of the object's class, which, if the object is itself a class, is a metaclass. So that's where you have to define it:
>>> class Test4(object):
... class __metaclass__(type):
... def __getitem__(cls, key):
... return 1
...
>>> Test4['a key']
1
There's no other way. To quote PEP20: There should be one-- and preferably only one --obvious way to do it.