How to access "self" inside the scope of a class? - python

I've crossed an interesting problem.
Suppose we have a class, and in its constructor we take a boolean as an argument. How can I define methods inside the class based on the instance's condition/boolean? For example:
class X():
def __init__(self, x):
self.x = x
if self.x == true: # self is unreachable outside a method.
def trueMethod():
print "The true method was defined."
if self.x == false: # self is unreachable outside a method.
def falseMethod():
print "The false method was defined."

You can't, but you can define methods with different names and expose them under certain circumstances. For example:
class X(object):
def __init__(self, flag):
if flag:
self.method = self._method
def _method(self):
print "I'm a method!"
Testing it:
>>> X(True).method()
I'm a method!
>>> X(False).method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'X' object has no attribute 'method'

No, because self refers to an instance, and there are no instances yet at the time the class is defined.
There are ways to achieve similar effects (like renaming, adding or deleting methods on a per-instance basis within __init__), but there's no real reason to do this anyway.

You cannot do that, but to define a method on the fly you can use types.MethodType:
from types import MethodType
def trueMethod(self):
print "The true method was defined."
def falseMethod(self):
print "The false method was defined."
class X():
def __init__(self, x):
self.x = x
if self.x:
self.trueMethod = MethodType(trueMethod, self, X)
elif not self.x:
self.falseMethod = MethodType(falseMethod, self, X)

You can create dict and on the bases of value you can access function like
def __init__(self, x):
self.x = x
self.my_dict = {True : lambda *a : print "True method", False: lambda *a: print "False method"}
Then you can access self.my_dict[self.x].

Related

what code should i write after the object definition to print all the fun method

class ApnaCollege():
def __init__(self,x,y):
self.x = x
self.y = y
print(self.x)
def fun(self):
print("I am a function with no argument")
def fun(self,x):
print("The function with an argument")
def fun(self,x,y):
print("The function with an two argument")
obj = ApnaCollege()
obj.fun()
obj.fun(3)
To see all the methods of an object defined by a class:
dir(obj)
You can find more info here: Ask Python: How to find all the methods of a given class in Python? including how to filter out dunder methods and get the methods you explicitly defined.

get return value from function in a class in variable python [duplicate]

If I have a class ...
class MyClass:
def method(arg):
print(arg)
... which I use to create an object ...
my_object = MyClass()
... on which I call method("foo") like so ...
>>> my_object.method("foo")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 1 positional argument (2 given)
... why does Python tell me I gave it two arguments, when I only gave one?
In Python, this:
my_object.method("foo")
... is syntactic sugar, which the interpreter translates behind the scenes into:
MyClass.method(my_object, "foo")
... which, as you can see, does indeed have two arguments - it's just that the first one is implicit, from the point of view of the caller.
This is because most methods do some work with the object they're called on, so there needs to be some way for that object to be referred to inside the method. By convention, this first argument is called self inside the method definition:
class MyNewClass:
def method(self, arg):
print(self)
print(arg)
If you call method("foo") on an instance of MyNewClass, it works as expected:
>>> my_new_object = MyNewClass()
>>> my_new_object.method("foo")
<__main__.MyNewClass object at 0x29045d0>
foo
Occasionally (but not often), you really don't care about the object that your method is bound to, and in that circumstance, you can decorate the method with the builtin staticmethod() function to say so:
class MyOtherClass:
#staticmethod
def method(arg):
print(arg)
... in which case you don't need to add a self argument to the method definition, and it still works:
>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo
In simple words
In Python you should add self as the first parameter to all defined methods in classes:
class MyClass:
def method(self, arg):
print(arg)
Then you can use your method according to your intuition:
>>> my_object = MyClass()
>>> my_object.method("foo")
foo
For a better understanding, you can also read the answers to this question: What is the purpose of self?
Something else to consider when this type of error is encountered:
I was running into this error message and found this post helpful. Turns out in my case I had overridden an __init__() where there was object inheritance.
The inherited example is rather long, so I'll skip to a more simple example that doesn't use inheritance:
class MyBadInitClass:
def ___init__(self, name):
self.name = name
def name_foo(self, arg):
print(self)
print(arg)
print("My name is", self.name)
class MyNewClass:
def new_foo(self, arg):
print(self)
print(arg)
my_new_object = MyNewClass()
my_new_object.new_foo("NewFoo")
my_bad_init_object = MyBadInitClass(name="Test Name")
my_bad_init_object.name_foo("name foo")
Result is:
<__main__.MyNewClass object at 0x033C48D0>
NewFoo
Traceback (most recent call last):
File "C:/Users/Orange/PycharmProjects/Chapter9/bad_init_example.py", line 41, in <module>
my_bad_init_object = MyBadInitClass(name="Test Name")
TypeError: object() takes no parameters
PyCharm didn't catch this typo. Nor did Notepad++ (other editors/IDE's might).
Granted, this is a "takes no parameters" TypeError, it isn't much different than "got two" when expecting one, in terms of object initialization in Python.
Addressing the topic: An overloading initializer will be used if syntactically correct, but if not it will be ignored and the built-in used instead. The object won't expect/handle this and the error is thrown.
In the case of the sytax error: The fix is simple, just edit the custom init statement:
def __init__(self, name):
self.name = name
Newcomer to Python, I had this issue when I was using the Python's ** feature in a wrong way. Trying to call this definition from somewhere:
def create_properties_frame(self, parent, **kwargs):
using a call without a double star was causing the problem:
self.create_properties_frame(frame, kw_gsp)
TypeError: create_properties_frame() takes 2 positional arguments but 3 were given
The solution is to add ** to the argument:
self.create_properties_frame(frame, **kw_gsp)
As mentioned in other answers - when you use an instance method you need to pass self as the first argument - this is the source of the error.
With addition to that,it is important to understand that only instance methods take self as the first argument in order to refer to the instance.
In case the method is Static you don't pass self, but a cls argument instead (or class_).
Please see an example below.
class City:
country = "USA" # This is a class level attribute which will be shared across all instances (and not created PER instance)
def __init__(self, name, location, population):
self.name = name
self.location = location
self.population = population
# This is an instance method which takes self as the first argument to refer to the instance
def print_population(self, some_nice_sentence_prefix):
print(some_nice_sentence_prefix +" In " +self.name + " lives " +self.population + " people!")
# This is a static (class) method which is marked with the #classmethod attribute
# All class methods must take a class argument as first param. The convention is to name is "cls" but class_ is also ok
#classmethod
def change_country(cls, new_country):
cls.country = new_country
Some tests just to make things more clear:
# Populate objects
city1 = City("New York", "East", "18,804,000")
city2 = City("Los Angeles", "West", "10,118,800")
#1) Use the instance method: No need to pass "self" - it is passed as the city1 instance
city1.print_population("Did You Know?") # Prints: Did You Know? In New York lives 18,804,000 people!
#2.A) Use the static method in the object
city2.change_country("Canada")
#2.B) Will be reflected in all objects
print("city1.country=",city1.country) # Prints Canada
print("city2.country=",city2.country) # Prints Canada
It occurs when you don't specify the no of parameters the __init__() or any other method looking for.
For example:
class Dog:
def __init__(self):
print("IN INIT METHOD")
def __unicode__(self,):
print("IN UNICODE METHOD")
def __str__(self):
print("IN STR METHOD")
obj = Dog("JIMMY", 1, 2, 3, "WOOF")
When you run the above programme, it gives you an error like that:
TypeError: __init__() takes 1 positional argument but 6 were given
How we can get rid of this thing?
Just pass the parameters, what __init__() method looking for
class Dog:
def __init__(self, dogname, dob_d, dob_m, dob_y, dogSpeakText):
self.name_of_dog = dogname
self.date_of_birth = dob_d
self.month_of_birth = dob_m
self.year_of_birth = dob_y
self.sound_it_make = dogSpeakText
def __unicode__(self, ):
print("IN UNICODE METHOD")
def __str__(self):
print("IN STR METHOD")
obj = Dog("JIMMY", 1, 2, 3, "WOOF")
print(id(obj))
If you want to call method without creating object, you can change method to static method.
class MyClass:
#staticmethod
def method(arg):
print(arg)
MyClass.method("i am a static method")
I get this error when I'm sleep-deprived, and create a class using def instead of class:
def MyClass():
def __init__(self, x):
self.x = x
a = MyClass(3)
-> TypeError: MyClass() takes 0 positional arguments but 1 was given
You should actually create a class:
class accum:
def __init__(self):
self.acc = 0
def accumulator(self, var2add, end):
if not end:
self.acc+=var2add
return self.acc
In my case, I forgot to add the ()
I was calling the method like this
obj = className.myMethod
But it should be is like this
obj = className.myMethod()

How can I call the metaclass's __call__?

Given the following example on an instance of a X class:
class X():
def __call__(self, incoming_list):
print incoming_list
X()([x for x in range(10)])
How can I obtain the same output by using the __call__ magic method from the class itself instead of the instance? Example:
X([x for x in range(10)])
Calling directly, as if passing to __init__. But, before it calls __call__ that calls __new__ that passes the arguments to __init__. How can I access that "metaclass __call__" ? Is it possible?
Just to make it easier to understand, this gives me the same output from up there:
class X:
def __call__(self, incoming_list):
print incoming_list
X().__call__([x for x in range(10)])
I want something like this:
class X:
def X.__call__(incoming_list): # Syntax Error
print incoming_list
X.__call__([x for x in range(10)])
I think you think too complicated.
Probably you want something like
class X:
def __init__(self, incoming_list):
self.data = incoming_list # to keep them for later, if needed
print incoming_list
X([x for x in range(10)])
Everything without a meta class, just on definition of the class.
If you need a meta class, you can do it like
class MC(type):
def __call__(self, *a, **k):
super(MC, self).__call
print a, k
r = super(MC, self).__call__(*a, **k)
print "R", r
return r
class X(object):
__metaclass__ = MC
def __init__(self, x): print "Init", x
Using it with
>>> X(1)
(1,) {}
Init 1
R <__main__.X object at 0x00000000022907B8>
<__main__.X object at 0x00000000022907B8>
shows that the meta-__call__ is called, which, in turn, calls __init__.
But I am sure that you don't need that and that you just want __init__.

The self parameter with a dictionary of functions within a class

I'm attempting to create a dictionary of executable functions within a class. But having trouble getting the self parameter to work correctly.
Consider the following code:
class myclass(object):
def x(self):
return 'x'
def y(self):
return 'y'
EF= {
'a':x,
'b':y,
}
def test(self):
print self.EF['a']()
When I attempt to execute the 'test' function of the class, I get an error around the number of parameters as it evaluates and executes one of the functions in the dictionary.
>>> class myclass(object):
... def x(self):
... return 'x'
... def y(self):
... return 'y'
... EF= {
... 'a':x,
... 'b':y,
... }
... def test(self):
... print self.EF['a']()
...
>>>
>>>
>>> m=myclass()
>>> m.test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in test
TypeError: x() takes exactly 1 argument (0 given)
I've tried a few variations, including this which doesn't work.
EF= {
'a':self.x,
'b':self.y,
}
The only thing that did work was when I explicitly passed self as a parameter, like this.
... def test(self):
... print self.EF['a'](self)
...
>>> m=myclass()
>>> m.test()
x
I've seen other questions about using a dictionary to index functions, but none from within a class.
Here are my questions:
What is the proper way to do handle the self parameter?
I'd prefer to move my dictionary constant outside of the class into my constants section. Can I do that, and if so how? Should I do that?
If I should/have to have my dictionary within my class, why can't I move it to the top of the class?
That's all I got. Thanks for the help.
What is the proper way to do handle the self parameter?
Python uses the self identifier in similar ways to other imperative languages using the this identifier, but it is explicit (as explicit is better than implicit!)
This allows you to use the class as either an instantiated object, or the static class itself.
For an instantiated version, you are probably looking for
>>> class myclass:
def __init__(self):
self.EF = {'a':self.x,'b':self.y}
def x(self):
return 'x'
def y(self):
return 'y'
def test(self):
print self.EF['a']()
>>> my_test_class = myclass()
>>> my_test_class.test()
x
I'd prefer to move my dictionary constant outside of the class into my constants section. Can I do that, and if so how? Should I do that?
If you wanted to use them as static method in a dict outside your class definition, you would need to use the #staticmethod decorator
>>> class myclass(object):
#staticmethod
def x():
return 'x'
#staticmethod
def y():
return 'y'
>>> EF = {'a':myclass.x,'b':myclass.y}
>>> EF['a']()
'x'
If I should/have to have my dictionary within my class, why can't I move it to the top of the class?
Any object attributes should be defined either in the __init__ function, or by explicitly setting them.
Having the dictionary in an init method will make it work
class Myclass(object):
def x(self):
return 'x'
def y(self):
return 'y'
def __init__(self):
self.EF= {
'a':self.x,
'b':self.y
}
def test(self):
print self.EF['a']()
m=Myclass()
m.test()
In reference to your questions. The class is kind of a dictionary or named tuple of attributes and executable functions. The functions themselves only define behavior. self is a sack of state related to your instance. if you save a pointer to that function somewhere else and provide it with a given self that is an instance of your class it should work as normal.
class MyClass(object):
def __init__(self, x):
self.x = x
def fun(self):
return self.x
i = MyClass(1)
print i.fun()
f = MyClass.fun
i2 = MyClass(2)
print f(i2)
When you call using the standard i.fun() all it's doing is passing i in implicitly as the selfargument.

class method with no arguments produces TypeError

This code:
class testclass:
def __init__(self,x,y):
self.x = x
self.y = y
self.test()
def test():
print('test')
if __name__ == '__main__':
x = testclass(2,3)
yields:
Error:
TypeError:test() takes no argument(1 given)
I'm calling the test function without any parameter, why does the error say that I have given one?
You call the methods as self.test(). You should mentally translate that to test(self) to find out how the call will be "received" in the function's definition. Your definition of test however is simply def test(), which has no place for the self to go, so you get the error you observed.
Why is this the case? Because Python can only look up attributes when specifically given an object to look in (and looking up attributes includes method calls). So in order for the method to do anything that depends on which object it was invoked on, it needs to receive that object somehow. The mechanism for receiving it is for it to be the first argument.
It is possible to tell Python that test doesn't actually need self at all, using the staticmethod decorator. In that case Python knows the method doesn't need self, so it doesn't try to add it in as the first argument. So either of the following definitions for test will fix your problem:
def test(self):
print('test')
OR:
#staticmethod
def test():
print('test')
Note that this is only to do with methods invoked on objects (which always looks like some_object.some_method(...)). Normal function invocation (looking like function(...)) has nothing "left of the dot", so there is no self, so it won't be automatically passed.
Pass self to your test method:
def test(self):
print('test')
You need to do this because Python explicitly passes a parameter referring to the instantiated object as the first parameter. It shouldn't be omitted, even if there are no arguments to the method (because of the error specified).
Python always passes the instance as the first argument of instance methods, this means that sometimes the error messages concerning the number of arguments seems to be off by one.
class testclass:
def __init__(self,x,y):
self.x = x
self.y = y
self.test()
def test(self): ## instance method
print('test', self)
if __name__ == '__main__':
x = testclass(2,3)
If you don't need access to the class or the instance, you can use a staticmethod as shown below
class testclass:
def __init__(self,x,y):
self.x = x
self.y = y
self.test()
#staticmethod
def test():
print('test')
if __name__ == '__main__':
x = testclass(2,3)
A classmethod is similar, if you need access to the class, but not the instance
class testclass:
def __init__(self,x,y):
self.x = x
self.y = y
self.test()
#classmethod
def test(cls):
print('test', cls)
if __name__ == '__main__':
x = testclass(2,3)

Categories