NameError: name 'self' is not defined Explain - python

I'm trying to understand how "self" works. In this first code I got error but I belive I did everything right. After that I try few more things to figure it but could not. What am I missing here?
class myClass:
def foo(self):
print('WORKED')
self.foo()
NameError: name 'self' is not defined
class myClass:
def foo(self):
print('WORKED')
foo()
TypeError: foo() missing 1 required positional argument: 'self'
class myClass:
def foo():
print('WORKED')
foo()
myClass.foo()
WORKED
WORKED
(in here pylint give warning that says "Method has no arguments")

The correct usage is:
class MyClass:
def foo(self):
print('WORKED')
def bar(self):
self.foo()
obj = MyClass()
obj.bar()
You have to define the method with the parameter self. It will be automatically passed as obj when calling obj.foo(). That is, obj.foo() is equivalent to MyClass.foo(obj).

Why?
class myClass:
def foo(s):
print('WORKED', s)
return s
s = foo(1)
print("Hello")
myClass.foo(2)
print(myClass.s)
Result:
WORKED 1
Hello
WORKED 2
1
So if you call foo() without self it will be considered as a class field. If you ommited field declaration (i.e. s = foo(1) being foo(1) directly) it will execute also (as your code) but will not store result anywhere.
You cannot s = self.foo(1), because self will not be defined outside a member function. However, you can call it directly s = foo(1) and store in member s

Others have provided examples of code which runs, but I think there's a deeper issue of not understanding how Python works.
The thing to understand here is that unlike other languages like Java or C#, in Python the "body" of a class is a block of code which gets executed during the creation of the class.
class creates a special scope, then all the inside the body is run, then the class is created using all the symbols collected in the class body. It's also different from Ruby where first the class is created then the body is executed (and it has a self representing the class itself and you can call methods like attr_accessor): in Python first the body is executed then the class is created.
An other thing to note is that in Python self is not exactly magical, rather when you write obj.foo() Python executes it as type(obj).foo(obj). Technically you don't even have to call the first parameter self.
This means:
in your first snippet, right after your defined the method you tried to call it on something which doesn't even exist a this point (you've not created a self you could call)
in your second snippet, the function exists in the scope but it's not been converted to a method yet, so it's still waiting for one positional parameter.
in your third snippet, the function exists in the scope and takes no parameters and you can call it, however if you try to call it on an instance afterwards it's not going to work properly
PS: essentially you can think of:
class Foo:
...
as a shorthand for
def Foo_body:
...
return locals()
Foo = type("Foo", (object,), Foo_body())

Related

How to define a function where it doesn't matter whether you call the class

I am writing a program similar to the short program below:
class Class():
def __init__(self):
pass
def foo():
pass
Whenever I call foo as Class.foo() everything inside foo works fine.
However, when I call it as Class().foo(), then I get an error: by calling Class I give foo an extra argument, self.
If I added the argument self to foo, then it won't work if I call the function as Class.foo().
How can I avoid this? Any help would be greatly appreciated :)
It looks like foo should be a staticmethod.
class Class:
#staticmethod
def foo():
pass
print(Class.foo()) # -> None
print(Class().foo()) # -> None
P.S. I can expand on this if needed. The question is a bit vague.

Python decorator with same name as an instance method

I have a very similar question to this except I would like to name my function property
so for example Id like to do something like:
class ThingWithProperties(object):
def property(self, a):
print("in property", a)
#property
def test(self):
print("in test")
t = Testing()
t.property(1)
t.test()
But I get the following error:
Traceback (most recent call last):
File "test.py", line 5, in <module>
class ThingWithProperties(object):
File "test.py", line 10, in ThingWithProperties
#property
TypeError: property() missing 1 required positional argument: 'a'
Could someone please explain why this is happening? As well as how to work around it (without renaming my instance method)?
This is happening because by defining a method called property, you are shadowing the builtin property within the scope of the class declaration. Hence when you write #property, your method is called to decorate test as opposed to the builtin property.
You could use the __builtin__ module to explicitly use the builtin property:
class ThingWithProperties(object):
def property(self, a):
print("in property", a)
#__builtin__.property
def test(self):
print("in test")
Though I personally always avoid shadowing builtins, even if they are only shadowed in a limited scope, as is the case here.
To be a little more clear about the "shadowing" going on, try running this in your interpreter:
foo = 42
print(foo)
class Test:
foo = 73
print(foo)
print(foo)
There are two points to make here: First, some might be surprised that we can print things in a class definition. The point is that a class definition is a code block like any other, and you can write for-loops and print all you'd like, and whatever variables or functions you create are gathered together into a class dictionary when it comes time to actually create the class.
The second point is that the class definition creates a new scope, and the value of foo inside the scope is different than outside. That is, the above prints 42, then 73, then 42 again.

How does Python know the instance variable without defining __init__?

Let us consider the following example:
class X:
def run(self):
print("An example.")
X().run()
The output is:
> An example.
But when we omit the reference to the instance:
class X:
def run():
print("An example.")
X().run()
The output is:
TypeError: run() takes 0 positional arguments but 1 was given
When we instantiate the class, __ new __ gets called and the instance is created, ok. But how it requires an instance without defining __ init __? (I'm surprised because, I've always written __ init __ thinking that it was responsible for defining the convention / self name for referencing the variable). I'm confused.
When you call instance.run() if implicitly calls run(instance) which is why you're receiving the error:
TypeError: run() takes 0 positional arguments but 1 was given
That's also the reason why instance methods should have self as the first argument.
Second, you're using the old way of declaring a class - class X:
The new way1 is class X(object): but regardless if you're using the new/old annotation, the call X() will return an instance of the class, even in case you didn't define __init__.
And third, if you want to make it a class method you can either do what Pynchia suggested in the comment above (annotate the method with #staticmethod) or declare the method as a class method by specifying that the first argument is cls and annotating it as a class-method:
class X:
#classmethod
def run(cls):
print "a"
X.run() # prints a
1. According to Mark's comment below, in Python 3 we return to the "old way" of declaring a class. Good to know - thanks Mark!

Python class variable changed a function into a method, why?

Why does Python turn a free function into an unbound method upon assignment to a class variable?
def make_func(s):
def func(x):
return '%s-%d' % (s, x)
return func
class Foo(object):
foofunc = make_func('foo')
So this works as expected: (returns "dog-1")
make_func('dog')(1)
But this fails with:
Foo.foofunc(1)
TypeError: unbound method func() must be called with Foo instance as first argument (got int instance instead)
Upon closer inspection, Python turned the "inner" function func inside make_func into a method, but since there's no self, this method will never work. Why does Python do this?
>>> import inspect
>>> inspect.getmembers(Foo, inspect.ismethod)
[('foofunc', <unbound method Foo.func>)]
Python can't tell "how" you assigned a method to a class attribute. There is no difference between this:
class Foo(object):
def meth():
pass
and this
def func():
pass
class Foo(object):
meth = func
In both cases, the result is that a function object is assigned to a class attribute named 'meth'. Python can't tell whether you assigned it by defining the function inside the class, or by "manually" assigning it using meth = func. It can only see the "end result", which is an attribute whose value is a function. Either way, once the function is in the class, it is converted to a method via the normal process that notices functions in class definitions and makes them into methods.
class Foo(object):
foofunc = make_func('foo')
foofunc is a class variable, not a method (for which you need the 'def'). And you initialize it with the result of make_func(...), so it won't change again.
If you want to call Foo.foofunc, you need to assign foofunc = make_func without a parameter.

Dealing with class inheritance in python

Can someone explain why I'm getting the error:
global name 'helloWorld' is not defined
when executing the following:
class A:
def helloWorld():
print 'hello world'
class B(A):
def displayHelloWorld(self):
helloWorld()
class Main:
def main:
b = B()
b.displayHelloWorld()
I'm used to java where class B would obviously have a copy of class A's method "helloWorld" and thus this code would run fine when executing main. This however appears to think class B doesn't have any method called "helloWorld"
Missing the self before the helloWorld(). The self keyword means that this an instance function or variable. When class B inherits class A, all the functions in class A can now be accessed with the self.classAfunction() as if they were implemented in class B.
class A():
def helloWorld(self): # <= missing a self here too
print 'hello world'
class B(A):
def displayHelloWorld(self):
self.helloWorld()
class Main():
def main(self):
b = B()
b.displayHelloWorld()
You need to indicate that the method is from that class (self.):
class B(A):
def displayHelloWorld(self):
self.helloWorld()
Python differs in this from Java. You have to specify this explicitly in Python whereas Java accepts implicitly as well.
I don't know what is the version of python used in this example but it seems that syntax looks like python3. (except print statement which looks like python2.x)
Lets suppose that this is python3
I would say that helloWorld is class method of class A and It should be called as class attribute. As soon as this function is in class namespace It can be accessed outside this class only using owner class.
A.helloWorld()
or
B.helloWorld()
or
self.__class__.helloWorld()
You can't call it as bound method in this case because self argument will be passed and as soon as your function doesn't expect it it will fail.
there is possibility that helloWorld is method of A and self parameter is just missed
in this case this method can be called as follow:
self.helloWorld()
or
A.helloWorld(self)

Categories

Resources