python function behaves differently - python

Declaring a class with method 'print' with param 'self':
class First:
def print(self):
print('working')
return 2
Trying to call the method without instantiating the class:
First.print() getting below message:
TypeError: print() missing 1 required positional argument: 'self'
Now when instantiating the class and accessing the method: it's working.
first = First()
first.print()
# working
# 2
Now defining the same class without any param in method print:
class First:
def print():
print('working')
return 2
Calling the same method without instantiating the class and it's working:
First.print()
# working
# 2
Without defining the method param, python method behaving like Static. Is it true or something else?

self refers to the bound variable or object. so it needs instantiation. where as without self method becomes static (class method in python context) and can be called using Class Name.
Also you should write #classmethod decorator above the method definition. so that it is clearly state that it is a classmethod.
class First:
#classmethod
def print(cls):
print('working')
return 2
First.print()
For your reference
https://medium.com/quick-code/understanding-self-in-python-a3704319e5f0

In the first case, it is a function of one parameter. So, Class.f() fails. In the second example, it is a function of zero parameters. So, Class.f() works.
When you create an instance, the first parameter is automatically bound to that instance, and you need to pass n-1 parameters. So, it works in your first example, but it won't work in your second.

Related

Passing in "self" as a parameter in function call in a class (Python)

I defined a class and within that class, created some methods. In one of the methods I wish to call another method. What is the reason that I cannot call the method by placing "self" into the argument? For example, method2(self).
There are languages that let you write method2() as a shorthand for (what in Python would be) self.method2(), but you can't in Python. Python doesn't treat the self argument as special inside the function (except when calling super()).
In Python, method2(self) first of all looks up method2 in the current scope. It seems like it should be in scope, but it actually isn't because of Python's weird scoping rules. Nothing in any class scope is ever visible in nested scopes:
x = 1
class A:
x = 2
print(x) # prints 2
def method(self):
print(x) # prints 1
class B:
print(x) # prints 1
Even if method2 was in scope, calling it directly would call the method from the class currently being defined, not the overridden method appropriate to the dynamic type of self. To call that, you must write self.method2().
The self parameter is automatically passed in as the object you are calling the method from. So if I said self.method2(), it automatically figures out that it is calling self.method2(self)
You can call a method with self as an argument, but in this case the method should be called as the method of the class, not the instance.
class A:
def method1(self):
print(1)
def method2(self):
A.method1(self)
a = A()
a.method2()
# 1

Python decorating classes and preserving name

I am trying to create decorator for classes which takes parent_klass as an argument and modifies original class by inheriting parent_klass and returns it. See below implementation of this idea:
class HelperClass:
def helper_method(self):
print("helper method...")
def inherit_from(parent_klass):
def wrapper(cls):
class DecoratedClass(cls, parent_klass):
pass
return DecoratedClass
return wrapper
#inherit_from(HelperClass)
class Foo:
pass
f = Foo()
f.helper_method() # prints helper method...
print(Foo.__name__) # prints DecoratedClass
Above code works as I expected except the last print line. My problem is that __name__ attribute of original class (Foo) is not preserved and replaced by DecoratedClass. How can I apply functools.wraps functionality in this case? Is there any other way than using wraps function?
EDIT: Actually, I want to use this decorate in Django project, in which __name__ attribute is important for database mapping. This decorator is intended to generate dynamic models that also contains custom managers. Simply inheriting the class without decorator does not solve my problem, since supplied argument ('parent_klass' in this case, but 'custom queryset' class in actual implemetation), is also used in bases class's (Foo) methods.

Python AttributeError: Object has no attribute in Unittest

I have 2 scripts, 1st is All_Methods, and another is All_Testcases, as I am using unittest framework, so here we go.
All_Methods is like:
class All_Services():
def abc(self):
x =1
def bca(self):
print "My Name is Taimoor"
self.abc()
def cba(self):
self.bca()
and on another script which is All_TestCases is like this:
from All_Methods import All_Services as service
class All_TestCases(unittest.TestCase):
def test_1_running_method(self)
service.cba(self)
Exception showing is:
AttributeError: 'All_TestCases' object has no attribute 'bca'
Kindly someone tell me, what I am missing here?
Thanks.
You are not using classes in the usual way when you pass in self to methods that you call on the class. Common is to call the methods on instances of the class and getting the self argument implicitly.
When you call Method.running_query_Athena(self) self is an instance of All_TestCases which does not have the method connecting_Athena.
Did you mean for All_TestCases to derive from All_Methods?
Why is All_Methods a class at all?
Use proper indentation since python is solely based on the basis of how the code is indented.
Please, Please use proper naming conventions; as advised under PEP 8.
You're trying to access an instance method without an instance.
Try the following:
class MyClass:
def my_instance_method(self):
return True
#classmethod
def my_class_method(cls):
return True
#staticmethod
def my_static_method():
return True
This won't work:
>> MyClass.my_instance_method()
TypeError: my_instance_method() missing 1 required positional argument: 'self'
but these will since they are not bound to a class instance being created.
MyClass.my_class_method()
MyClass.my_static_method()
An instance method requires that you instantiate the Class; meaning you use:
MyClass().my_instance_method()
Since you seem to want to set response_id on the class instance; using the self argument which denotes the class instance to get the response_id. - I suggest that you use an instance method and instantiate the class as shown above (note the () after the class name)
Kindly do fix your formatting in the question.
There are quite a few things wrong with the code in the example, but putting that aside.
The error is caused by passing an instance of class A as the self argument to a (non-static) method of class B.
Python will attempt to call this method on the instance of class A, resulting in the missing attribute error.
Here is a simplified example of the problem:
class A:
def is_ham(self):
# Python secretly does `self.is_ham()` here,
# because `self` is the current instance of Class A.
# Unless you explicitly pass `self` when calling the method.
return True
class B:
def is_it_ham(self):
# Note, `self` is an instance of class B here.
return A.is_ham(self)
spam = B()
spam.is_it_ham()

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!

How to create a decorator function with arguments on python class?

I want to create a decorator function to operate on a python class, with the ability to pass additional arguments. I want to do that before the class gets instantiated. Here is my approach:
def register(x,a):
print x,a
#register(5)
class Foo(object):
pass
with x being the class and a the additional argument. But I get a
TypeError: register() takes exactly 2 arguments (1 given)
What I want is some way to get hold of the class Foo and additional arguments at the time the class is defined, before the class is instantiated.
You need to do it this way:
def makeDeco(a):
def deco(cls):
print cls, a
return cls
return deco
>>> #makeDeco(3)
... class Foo(object):
... pass
<class '__main__.Foo'> 3
You can use functools.wraps and so forth to spruce it up, but that is the idea. You need to write a function that returns a decorator. The outer "decorator-making" function takes the a argument, and the inner decorator function takes the class.
The way it works is that when you write #makeDeco(3) it calls makeDeco(3). The return value of makeDeco is what is used as the decorator. That is why you need makeDeco to return the function you want to use as the decorator.

Categories

Resources