I've searched a lot about how to reuse a method from a class in the main.py file. i got some similar and basic solutions but in my case is a bit different.
/lib/module.py
class Myclass:
def __init__(self, x):
self.thisX = x
def check(self):
if self.thisX == 2:
print("this is fine. going to print it")
self.printing()
# this method will use in this class and must use from the main.py
# the parameter "z" is gonna use only when the method will call from main.py
def printing(self, z):
if z == 1 :
print("we got ", z)
else:
print(self.x)
/main.py
from lib.module import Myclass
# this is how i use the check() method once in my main.py
Myclass(2).check()
# the Myclass() gets "2" only once at the beginning of the program...
# i don't wanna pass "2" to the Myclass() everytime that i wanna use the printing() method...
c = Myclass()
c.printing(1)
error
TypeError: __init__() missing 1 required positional argument: 'x'
testing:
if i don't use the def init(), everything will be fine. but the problem is i need to keep it
This line in main.py:
c = Myclass()
Calls this function:
class Myclass:
def __init__(self, x):
self.thisX = x
Every time you create an instance of Myclass it will call the __init__() function. You declared it to take 2 arguments: self and x. self is always passed implicitly because it's a class, but you need to give it an argument 'x'.
So you can change main.py to this for example:
c = Myclass(2) # here x = 2
c.printing(1)
Please read this for more information
Also, in general, class names are written in CapWords style so it's a good idea to call your class MyClass instead of Myclass
Edit:
Since you don't want to pass x to __init__() and you want to set x from main.py you can try something like this:
class Myclass:
x = 0
def check(self):
if self.x == 2:
print("x is 2")
from main.py you can do:
Myclass.x = 2; #this only needs to be done once
Myclass().check()
Output:
x is 2
I think #richflow 's answer hit the point. If some variable is to be shared by all instances of a class, it's logical to assign its value using Myclass.x = new_number. Then all instances of this class will know the change.
If you really want to optionally change x in the __init__ method of an instance, you can still do it. Combining with #richflow's codes, it can look like the following.
class Myclass:
x = 0
def __init__(self, x=None):
if x is not None:
Myclass.x = x
# other codes for initializiing the instance
def check(self):
if Myclass.x == 2:
print("this is fine. going to print it")
def printing(self, z=0):
if z == 1 :
print("we got ", z)
else:
print(Myclass.x)
I tried not to change too much from your codes. Your main.py should work correctly with this class definition. However, the design looks a bit weird to me. Probably that's because I didn't understand clearly what the check and printing methods are really doing, and what the argument z is really doing in printing methods. If you provides more insights, probably people can help you with a better design.
Related
I have a question regarding parametrizing the test method with another method that returns the list of test data that I want to use in my test:
When I execute code in this way:
class Test:
#pytest.mark.parametrize("country_code", get_country_code_list())
def test_display_country_code(self, country_code):
print(country_code)
#classmethod
def get_country_code_list(cls) -> list:
return [1, 2, 3]
I get error: Unresolved referency: get_country_code_list. It doesn't make a difference if get_country_code_list method is a static method, class method or self.
But if I put the method get_country_code_list() above the test method, I don't get this error.
Does the order of test methods make a difference in Python?
Yes, the order in which you do things is important.
Functions are just like variables in that manner.
Working Example Variables
x = 3
y = 5
z = x + y
Works perfectly fine, because everything is done according to order.
Broken Example Variables
x = 3
z = x + y
y = 5
Doesn't work, of course, because y is neither declared nor defined when y is needed for the initialization of z.
Works just the same with functions
def bar():
return foobar()
def foo():
return bar()
foo()
def foobar()
return 5
Function foo can call function bar perfectly fine, but bar can't call foobar, because foobar is not defined yet at the execution point of foo().
This isn't a test-specific issue only.
You need to understand that #pytest.mark.parametrize is a decorator, a syntactic sugar of a class / method. When you pass an argument in a class / method, it expects the argument to be defined. Hence why this works:
def display(arg):
return print(arg)
word = "Hello World!"
display(word)
while this does not:
def display(arg):
return print(arg)
display(word)
word = "Hello World!"
Here's an example of a class-based decorator:
class MyDecorator:
def __init__(self, decor_arg):
self.decor_arg = decor_arg
def __call__(self, fn):
def wrapper(fn_arg):
return fn_arg
return self.decor_arg
def message(arg):
return f"The parameter passed is {arg}"
#MyDecorator(message)
def display(arg):
return arg
print(display("Hello World!"))
The print result:
The parameter passed is Hello World!
Given the explanation above, I'm sure you can see why the method message needs to be placed before display. If your editor has IntelliSense, changing the order of the two methods will display an error outline on #MyDecorator(concat) with the message "undefined name 'message'" or something similar.
I will get straight to the point. I have been trying to find different ways in which I can check if an instance attribute exists in a method of a class which has not been called from the instance of the class.
Consider the following example:
class Main:
def thing1(self):
self.x = 10
m = Main()
print(m.x)
This code above will not work, until I call the method, e.g:
class Main:
def thing1(self):
self.x = 10
m = Main()
m.thing1()
print(m.x)
or
class Main:
def __init__(self):
self.thing1()
def thing1(self):
self.x = 10
m = Main()
print(m.x)
I want to know if there is a way I can check if this instance attribute exists in the method without having to call it.
I have tried using:
hasattr()
dir()
__ dict __
None of them will show that I have a instance attribute called 'x' in thing1
As well as this, I would greatly appreciate it if you could show me how I could check if an instance attribute in a method exists through another method.
class Main:
def thing1(self):
self.x = 10
def check(self):
# Is there a way I can check if 'x' exists in the method names thing1, without having to call it.
m = Main()
Thank you for taking the time to read this question, and I hope that you have a great day!
Indeed hasattr() definitely works. See interactive example below:
>>> class Main:
... def thing1(self):
... self.x = 10
...
>>> m = Main()
>>> hasattr(m, 'x')
False
>>> m.thing1()
>>> hasattr(m, 'x')
True
>>> print(m.x)
10
It's worth noting, though, that attributes should be initialized in the constructor. It's good practice to use __slots__ to declare attributes, but they must still be initialized. Also, class variables (attributes) are initialized outside the constructor. See example below:
class Main:
c = 5
__slots__ = ('x', 'y')
def __init__(self):
self.y = 12
def thing1(self):
self.x = 10
m = Main()
print(hasattr(m, 'x'))
print(hasattr(m, 'y'))
print(m.c)
Output:
False
True
5
After reading the question again and additional comments, it seems that you want to access an attribute that is initalized in a method, without actually calling said method. This is not possible because the attribute won't actually exist until it is initialized.
The only way I can think of to determine if the attribute would exist after the method call, is to read the code of the function in your program and check for the presence of the attribute. This is one crude example, which by no means is guaranteed to always work:
import inspect
lines = inspect.getsource(Main.thing1)
print('self.x' in lines)
The above, would print True for the code in question. I cannot think of a use case where this would be useful and strongly discourage it, but it's good to know the capabilities of Python.
I want to define an attribute of a class and then use it as argument of a method in the same class in the following way
class Class1:
def __init__(self,attr):
self.attr=attr
def method1(self,x=self.attr):
return 2*x
It returns an error: NameError: name 'self' is not defined
How can I define the method in such a way that whenever I don't write x explicitly it just uses the attribute attr ?
In the example, what I mean is that I would like to have
cl=Class1()
print cl.method1(12) # returns '24'
cl.attr= -2
print cl.method1() # returns '-4'
This is because in method1, you just define the self variable in the first argument. And the self variable will only useable in the function body.
You probably think self is a special keyword. Actually self is just anormal varialbe like any variable else.
To solve the issue:
Use default value in function defination and check it in the function body:
class Class1:
def __init__(self):
self.attr = 3
def method1(self, x=None):
x = self.attr if x is None else x
return 2*x
cl = Class1()
print(cl.method1(12))
cl.attr=-2
print(cl.method1())
Result:
24
-4
In your code it seems like you are naming x as an argument you are passing to the function when in reality you are giving the init function the value, try the following code:
class Class1:
def __init__(self,attr = 3):
self.attr=attr
def method1(self):
y = (self.attr)*(2)
return y
When you call the function you should do it like this:
result = Class1(4)
print(result.method1())
>>8
P.T. Im kind of new in Python so don't give my answer for granted or as if it's the best way to solve your problem.
Sorry, Im new to Python and have a basic q
I have 2 python files
FileA.py
Class ABC:
def __init__(self, loggingLevel = 20):
self.data = None
logging.basicConfig(level=loggingLevel)
pass
def asd(self, text)
*
*
if __name__ == '__main__':
X=ABC(10)
Y=X.asd(text)
I have another file FileB.py from where i want to call function asd. I have the parameter 'text' to pass, but what should i pass for parameter 'self'. tried many options , but when it goes to File A, its failing as the value of self is not correct
self is implicitly passed if you have a reference to an instance of the containing class. In other words, you can do the same thing that you did in main in the FileB.py:
FileB.py
from FileA import ABC
X = ABC(10)
Y = X.asd(text)
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)