I have a python class and couple of functions, 1st calling 2nd. However, 2nd is never getting called. Also the line after _method2() invocation is never executed.
class call_methods():
def _method1(self, context):
print "Now call method 2";
this._method2(context);
print "Finish";
return {}
def _method2(self, context={}):
print "method 2 called"
return {}
Output:
Now call method 2
Only 1st print statement comes out.
The question is similar to Function Not getting called but solution suggested there doesn't seem to apply to this.
this._method2(context); ===> self._method2(context)
this does not exist in python.You have to use self.Also ; is not needed.Instead follow proper indentation.Modify your second function as
def _method2(self, context={}):
You have the name this which is not defined, so Python will complain. You can alter your second method _method2() to take the argument self which, in Python, is a convention signifying the instance of a class you have created and want to reference:
class call_methods:
def _method1(self, context):
print "Now call Method 2"
self._method2(context)
print "finish"
return {}
def _method2(self, context={}):
print "Method 2 Called"
return {}
If you want to call _method2 via _method1 using the instance of a class you have created, you must again provide the self argument in the call to _methdo2() that references the instance, this is done implicitly by calling the function on the self argument of _method1.
Your output after altering will be:
In [27]: cls1 = call_methods()
In [28]: cls1._method1("con")
Now call Method 2
Method 2 Called
finish
Out[28]: {}
P.S: No need for parentheses () when declaring a class, it makes no difference. You might want to take a look at New Style Classes in Python 2
It should be:
class call_methods():
def _method1(self,context):
print "Now call method 2";
this._method2(context);
print "Finish";
return {}
def _method2(self, context={}):
print "method 2 called"
return {}
Related
To demonstrate what I want to do, here's a piece of code:
class CallOnce(object):
called=False
def web_service(cls,macid):
if cls.called:
print ("already called")
return
else:
# do stuff
print ("called once")
cls.called = True
return macid
To test our class, I proceed as follows:
for i in range(2):
macid = "123"
call_once_object = CallOnce()
call = call_once_object.web_service(macid)
print(call)
The expected result should be like this:
called once
123
already called
Except I got this as a result:
called once
123
called once
123
The idea is to store the value 123 only once in the call variable without using global variable.
cls.called is an attribute of the instance, not the class. Each time you create a new object, it gets its own attribute, which defaults to False.
If you want to share this among all the instances, you should use CallOnce.called, not cls.called.
BTW, the conventional name for the first argument of instance methods is self. cls is used for class methods.
So you're trying to save some state. What you could do is use an object instead.
class Test():
def __init__(self):
self.called = False
def call_me_maybe(self):
if (not self.called):
print('Hey, you called?')
self.called = True
else:
print("Stop calling me it's getting weird")
test = Test()
test.call_me_maybe() #-> Hey, you called?
test.call_me_maybe() #-> Stop calling me it's getting weird
You don't need a class for this. Functions can have their own attributes.
def web_service(macid):
if hasattr(web_service, 'called'):
print ("already called")
return
else:
# do stuff
print ("called once")
web_service.called = True
return macid
web_service(5)
web_service(6)
Output:
called once
already called
I am new to Python with Java background, the concept of "self" in function confuses me. I understand first argument "self" mean the object itself, but I do not understand how Python make this work. I also know that I could use "this" or "that" or "somethingElse", and Python would still understanding I mean to use the object.
I copied some code from a reddit post:
class A():
def __init__(self):
self.value = ""
def b(this):
this.value = "b"
def c(that):
that.value = "c"
a = A()
print(a.value)
a.b()
print(a.value)
>>>"b"
a.c()
print(a.value)
>>>"c"
How do python knows I do not mean to use an object here in the first argument? For example I modified the above code a bit:
class A():
def __init__(self):
self.value = ""
def b(this):
this.value = "b"
def c(that):
that.value = "c"
def somethingElse(someObjectIWantToPass):
someObjectIWantToPass.value = "still referring A.value"
class B():
def __init__(self):
self.value = ""
a = A()
print(a.value)
a.b()
print(a.value)
a.c()
print(a.value)
a.somethingElse()
print(a.value)
b = B()
a.somethingElse(b)
print (b.value)
And it broke:
b
c
still referring A.value
Traceback (most recent call last):
File "D:/Documents/test.py", line 32, in <module>
a.somethingElse(b)
TypeError: somethingElse() takes 1 positional argument but 2 were given
A method's first argument is always1 its instance. Calling it self is idiomatic in Python but that name is strictly convention.
class A():
def some_method(me): # not called `self`
print(str(id(me))
a = A()
a.some_method()
print(id(a))
If you're trying to pass another arbitrary object in, it has to be the second argument.
class B():
def another_method(self, other):
print(id(other))
b = B()
b.another_method(a)
print(id(b)) # different!
print(id(a)) # the same.
1 Not actually always. #classmethod decorated methods use cls as their first argument, and #staticmethod` decorated methods have nothing passed to its first argument by default.
class C():
#classmethod
def some_classmethod(cls, other, arguments):
# first argument is not the instance, but
# the class C itself.
#staticmethod
def something_related(other, arguments):
# the first argument gets neither the instance
# nor the class.
You are too focused on syntactic sugar. Just realize that the first parameter in a non static member function in python is the reference to the current object. Whether you want to call it this, that, foobar, poop, it doesn't matter. The first parameter of a member function is considered the reference to the object on which the method is called.
The use of self is just a universal way everyone has understood it and the way Python recommends - a convention if you may.
The same goes for **kwargs and *args. These are simply conventions that have permeated the Python ecosystem and everyone just uses it that way, but it doesn't mean you can't give them a different name.
Your last example broke because the function you are calling (A.something) does not take any parameters. This will make sense if you understood what I had said earlier about first parameter in non static member function being a reference to the object on which the method was called.
I'd like to know whether my method is called by the user directly or by another method. To make it less abstract:
class myclass():
def __init__(self, ...):
....
def method1(self, ...):
...
--- some if statement --
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(...)
return x*2
myinstance = myclass(...)
myinstance.method1(...)
--> 'Hello'
myinstance.callmethod(...)
--> -
Hopefully my class makes clear what I'd like to do: When the user calls 'method1' the print statement shall be executed but if 'method1' is called by another method like 'callmethod' the print statement shall not be executed. Therefore I need 'some if statement' which checks whether 'method1' is called by the user directly or by another method. Thanks for you help!
No, and you don't want to do this.
If you want to change behaviour depending on the way a method is called, then you need to use a parameter. You can use a default value to make this simpler, for example:
def method1(self, do_print=True):
...
if do_print:
print "Hello"
return something
def callmethod(self, ...):
x = self.method1(do_print=False)
return x*2
Now, calling myinstance.method1() will print, whereas myinstance.callmethod() will not.
It's actually achievable using the python inspector, like e.g.:
import inspect
class myclass():
def __init__(self):
pass
def method1(self):
(frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1]
if function_name == '<module>':
print "Hello"
return 2
def callmethod(self):
x = self.method1()
return x*2
myinstance = myclass()
myinstance.method1()
myinstance.callmethod()
but I agree with Daniel it's not an elegant way to achieve the result as it hides some behaviour.
For further details also see: this post
I found the below code from a website while practicing basic python scripting. From the below code I was able to understand the class and instance and first print statement.
But I do not understand the concept used behind second and third print statement. How can an instance(in the below code polly) can be passed as an argument to a class's method? Is there any option in python that we can pass this like that?.
class Pet(object):
def __init__(self, name, species):
self.name = name
self.species = species
def getName(self):
return self.name
def getSpecies(self):
return self.species
def __str__(self):
return "%s is a %s" % (self.name, self.species)
polly = Pet("Polly", "Parrot")
print "Polly is a %s" % polly.getSpecies()
Polly is a Parrot
print "Polly is a %s" % Pet.getSpecies(polly)
Polly is a Parrot
print "Polly is a %s" % Pet.getSpecies()
Traceback (most recent call last):
File "", line 1, in
TypeError: unbound method getSpecies() must be called with Pet instance as first argument (got nothing instead)
In fact, instance.instance_method() will turn into TheClass.instance_method(instance) internally, the self refers to the instance itself. so the first and the second versions are equals to each other.
a simple example:
def getSpeciesGlobal(some_object): # a normal function
return some_object.species
polly = Pet("Polly", "Parrot")
polly.species # "Parrot"
getSpeciesGlobal(polly) # "Parrot"
# if we assign this function to the class.
Pet.getSpeciesGlobal = getSpeciesGlobal
Pet.getSpeciesGlobal(polly) # "Parrot"
# the original way in your question
polly.getSpecies() # "Parrot"
Pet.getSpecies(polly) # "Parrot"
In Python, a class can be treated as a bag of properties. See below:
>>> class Stuff:
... pi = 3.14
... def foo(x, y):
... return x + y
... bar = lambda s: s * 2
...
>>> Stuff.bar(4)
8
>>> Stuff.foo(5,6)
11
>>> Stuff.pi
3.14
In this example, Stuff is just a bunch of random objects. So Stuff.bar refers to the actual function bar. Instances of a class have a different behaviour: When a function is accessed, it automatically gets converted to a bound method. This means that the instance is automatically passed as the first argument.
When you call Pet.getSpecies(polly), polly will be passed in as the self parameter. There's no magic to self, it's just another parameter. The magic is when you access polly.getSpecies and get a <bound method Polly.getSpecies of <__main__.Polly object at 0x7f946cd14b38> instead of a <function Polly.getSpecies at 0x7f946cd1e048>.
There's also the #classmethod decorator, which receives the class as the first argument instead of the instance, as well as making code easier to understand by clearly delimiting class methods and instance methods.
In the second print statement, polly is passed as the self argument to the class method. This happened implicitly in the first print statement.
On the third print, the class method is called, but there is no actual object with data to act on.
I know that this is super basic Python stuff, but the concept doesn't get into my mind.
I miss the fundamental reason and the structure to instantate an object under __init__()
This is a basic example, I do not understand the reason to put there self.tangerine="..." and why if I add self.order="order" everything works properly even if this parameter is not added into __init__(self, order)
class MyStuff(object):
def __init__(self):
self.tangerine="And now a thousand years between"
def apple(self):
print "I AM CLASSY APPLE!"
thing=MyStuff()
thing.apple()
print thing.tangerine
So to drill down on this simple example, I added a variable in init:
class MyStuff(object):
def __init__(self, order):
self.tangerine="And now a thousand years between"
self.order="order"
def apple(self):
print "I AM CLASSY APPLE!"
thing=MyStuff()
thing.apple()
print thing.tangerine
Now I get an error:
Traceback (most recent call last):
File "ex40_a.py", line 11, in <module>
thing=MyStuff()
TypeError: __init__() takes exactly 2 arguments (1 given)
Thought it seems to me that there are 2 arguments there (tangerine(self) and order).
Can anybody help me?
Anatomy of your second code snippet:
# Define class named MyStuff which inherits from object
class MyStuff(object):
# Define initializer method for class MyStuff
# This method accepts 2 arguments: self and order
# self will hold newly created instance of MyStuff
def __init__(self, order):
# Assign a string value to field tangerine of current instance
self.tangerine="And now a thousand years between"
# Assign a string value to field order of current instance
self.order="order"
# Note that second argument (order) was not used
# Define apple method for class MyStuff
# This method accepts 1 argument: self
# self will hold the instance of MyStuff
def apple(self):
# Print a string to standard output
print "I AM CLASSY APPLE!"
# Create instance of MyStuff
# Initializer is called implicitly and self is set to new instance
# Second argument (order) is missing, so you get exception
thing=MyStuff()
# Correct invocation would be
thing = MyStuff("some string value")
# Call method apple of MyStuff instance - statement correct but won't be reached
# due to former exception
thing.apple()
# Print value of field tangerine of MyStuff instance to standard output - again
# statement correct but won't be reached due to former exception
print thing.tangerine
Things to read about:
- actual and formal function/method parameters
- string literals
- and of course Python classes
Looks ok but I assume you want the order value fed into your object.
Also, generally you dont want to use print statements on your classes, instead return them and then print them else where in your code if you need
class MyStuff(object):
def __init__(self, order):
self.tangerine = "And now a thousand years between"
self.order = order
def apple(self):
return "I AM CLASSY APPLE!"
thing = MyStuff("I like strings and integer values")
print thing.order
print thing.tangerine
print thing.apple()
Output:
I like strings and integer values
And now a thousand years between
I AM CLASSY APPLE!
you specify the parameters you want to call your class with this:
def __init__(self, order):
self.order = order
if you dont want to call your class with anything and just use the string value do this:
def __init__(self):
self.order = "order"