Call a function outside any method but inside a class? - python

I'm trying to call a function to initialize my global class-level variables. Note that for some reason, I cannot write a constructor to do the job. (reason: I'm writing a test case for Tempest)
Code:
class my_class(ParentClass):
username = "abc"
password = "123"
hostname = self._get_hostname() # Error: self is undefined
hostname = _get_hostname() # Error: _get_hostname is undefined
def myFunct(self):
...
...
def _get_hostname(self):
...
...
Is it even possible in python to initialize global class-level variables with class functions?
Note 1: I have also tried to perform hostname initialization after the _get_hostname() function is written, but of no use.
Note 2: I can perform hostname initialization within a function such as:
def myFunction(self):
hostname = self._get_hostname()
# do something with hostname
...
But that would defeat the whole purpose of using a global class-level variable. I want to use a class-level variable for re-usage in other functions.

You cannot call instance methods for an instance that doesn't exist yet. If you want for it to be independent of any instance, and the functions you call don't require any information from the instance, you can use an #staticmethod decorator so you can call get hostname statically.

First: they are not global variables; they are class variables. (Globals are defined at the module scope.)
If _get_hostname() doesn't actually use self at all, you can do something a little sketchy: make sure it is defined before you use it, then call it with a fake first argument.
class my_class(ParentClass):
def _get_hostname(self):
...
hostname = _get_hostname(None) # Doesn't matter what
This works because when you call it inside the class statement, you can still treat it as a regular function. It just has to be defined before you use it, like any function.
If it actually does require a reference to an object (or even just the class), this won't work, because the class doesn't exist yet. The best you can do is either define a function prior to the class statement that doesn't use the class itself and call it. (This is also what you would do
if the previous option was possible but ... distasteful.)
def _get_hostname():
...
class my_class(ParentClass):
hostname = _get_hostname()
or defer initializing the class variable until after the class is defined. In this case, _get_hostname should probably be declared as a static method or a class method so that you don't have to instantiate the class just to initialize the class variable.
class my_class(ParentClass):
#classmethod
def _get_hostname1(cls):
...
#staticmethod
def _get_hostname2():
...
my_class.hostname = my_class._get_hostname1()
my_class.hostname = my_class._get_hostname2()

Related

Inner class usage python. Global name is not defined

I have a question about inner classes usage in python. I know that this is a bad practice but anyway. I am wondering about scope where inner class is defined. I got an error 'global name 'ClassName' is not defined'. My code snippet looks like this:
I discovered that to avoid getting this error I can use:
ClassWithEnum.EnumClass
instead of:
EnumClass
inside of doSomethingWithEnum() function. So I am wondering if there is any other way to make EnumClass defined inside of doSomethingWithEnum() function? And why there is no such error when I declare EnumClass as a default parameter in doSomethingWithEnum() function?
class ClassWithEnum(object):
class EnumClass(object):
...
def doSomethingWithEnum(self, m = EnumClass....):
...
Python class construction executes as code. The def statement is really a line of code being executed that creates a function. The class keyword introduces a namespace. Putting these two mechanisms together, it means that class EnumClass really creates an object by that name in the current namespace, not much different from what foo = 'bar' does, so within the same namespace you can refer to it by that name, which is what happens in the def statement.
Also compare:
class Foo:
bar = 'baz'
print bar
baz = bar
Every line of code inside a class block is a regular executable line of code.
Once your class definition is done, you're out of the ClassWithEnum namespace and cannot access EnumClass anymore simply by that name; it's now only available as ClassWithEnum.EnumClass; whether from "outside" the class or from within a function (any function, including class methods).
To get access to the class without typing its name from within the method you could do:
type(self).EnumClass
Or simply self.EnumClass, since properties are looked up up the chain.
When you are inside doSomethingWithEnum function, you are in the different namespace. To access anything that is defined in your class, like EnumClass, you should call self.EnumClass. If it were a class method, it would be cls.EnumClass.

Calling a static method inside of a Python class definition

I have a class definition which defines a static method. I have a field which I would like to initialize with the static method. My default thinking led me to this:
class SomeConcreteClass(object):
some_data = SomeConcreteClass.create_default_data()
#staticmethod
def create_default_data():
return 'Foo'
The problem is that when I run this, I get a NameError: name 'SomeConcreteClass' is not defined. It makes sense as the SomeConcreteClass is just being built. Does this mean I cannot use static init functions? Is there an alternate way which is recommended to handle such a situation?
The appropriate place for create_default_data would be outside the class entirely. Then your problems go away:
def create_default_data():
return 'Foo'
class SomeConcreteClass(object):
some_data = create_default_data()
If you really do want it as a static method inside the class that's alright too:
def _create_default_data():
return 'Foo'
class SomeConcreteClass(object):
some_data = _create_default_data()
create_default_data = staticmethod(_create_default_data)
but static methods aren't often used in Python because there's no need to put a function inside a class unless it operates on the class in some way.
If some_data is exactly the output of create_default_data (and assuming the latter is deterministic in the context of your call) then why not just make some_data a #property?
class SomeConcreteClass(object):
#property
def some_data():
return 'Foo'
Alternatively, but not equivalently, you could initialize some_data for each instance within __init__.
I don't think you want to do this. Don't forget that Python is not Java ™... attributes defined at class level are class attributes, not instance attributes. You almost certainly want the data to be instance-specific, so you should do this in the __init__ method. You can certainly call the classmethod from within that method, if you want to, or (better) just put the code in __init__.

python: set a class variable programmatically before other class variables get set?

i have a case where i create a class inside an outer function and then return that class. the class has a specified parent class. i would like that class variable to be accessible by class methods on the parent class, these methods are called at class initialization time. in summary, i need to be able to set a class variable (not hardcoded) so that it is available before initializing other, hardcoded class variables.
here's some sample code to make that clearer:
class Parent(object):
class_var = None
#classmethod
def get_class_var_times_two(cls):
return cls.class_var * 2
def outer_function(class_var_value):
class Child(Parent):
other_var = Parent.get_class_var_times_two() # <-- at this point, somehow Child's class_var is set to class_var_value
Not sure if this is even possible in python. Maybe class_var_value doesn't need to be passed through the outer function. I tried using metaclasses and forcing the variable through in the class attribute dictinoary, but couldn't figure out how to set class_var on Child early enough so that it was set prior to initializing other_var. If that was possible, then this would all work. Any thoughts are appreciated!
Edit: also considered making other_var a lazy property, but that isn't an option for my use case.
Calling Parent.get_class_var_times_two() calls the function with cls = Parent, and so consequently the value of Parent.class_var will be used (regardless of what context you call the function from).
So, what you want to do is call Child.get_class_var_times_two(). Trouble is, Child doesn't get defined until the class block finishes. You therefore need to do something like this (assuming you don't use a metaclass):
def outer_function(class_var_value):
class Child(Parent):
class_var = class_var_value
Child.other_var = Child.get_class_var_times_two()

How to call internal functions inside the constructor class?

Hello i have this code
class Test(object):
def start_conn(self):
pass
def __init__(self):
self.conn = start_conn()
But this code make this error:
NameError: global name 'start_conn' is not defined
If i write self.conn = self.start_conn() the program works without error, my question is, is a must to call with self the methods of the class when i'm creating a new instance? or is a desgin error from my side?
Thanks a lot
In short, it's a must. You have to refer to the container in which the methods are stored. Most of the time that means referring to self.
The way this works is as follows. When you define a (new-style) class
class FooClass(object):
def my_method(self, arg):
print self.my_method, arg
you create a type object that contains the method in its unbound state. You can then refer to that unbound method via the name of the class (i.e. via FooClass.my_method); but to use the method, you have to explicitly pass a FooClass object via the self parameter (as in FooClass.my_method(fooclass_instance, arg)).
Then, when you instantiate your class (f = FooClass()), the methods of FooClass are bound to the particular instance f. self in each of the methods then refers to that instance (f); this is automatic, so you no longer have to pass f into the method explicitly. But you could still do FooClass.my_method(f, arg); that would be equivalent to f.my_method(arg).
Note, however, that in both cases, self is the container through which the other methods of the class are passed to my_method, which doesn't have access to them through any other avenue.

Variable scope outside of classes

My text editor of choice is extensible through python plugins. It requires me to extend classes and override its methods. The general structure looks similar the snippet below. Note that the function signature is fixed.
ftp_client is supposed to be shared by instances of both classes.
ftp_client = None
class FtpFileCommand(sublime_plugin.TextCommand):
def run(self, args):
global ftp_client # does it reference the variable of the outer scope?
self.ftp_client = ftplib.FTP('foo')
# login and stuff
class FtpFileEventListener(sublime_plugin.EventListener):
def run(self, args):
global ftp_client # same for this
self.ftp_client.quit() #
Both of these classes are supposed to have one variable in common. What is the best practice in order to share variables?
Edit based on madjars answer:
FtpFileCommand.run is called first, instanciates ftp_client and works like a charm. FtpFileEventListener.run is called later and, can reference ftp_client perfectly but it is still None. Using the global keyword, does it add the variable as a member to self?
Yep, that's exactly how global works.
It seems to me you are doing it right, as it's done this way in some modules of the python standard library (fileinput, for example).
In this code:
global ftp_client # does it reference the variable of the outer scope?
self.ftp_client = ftplib.FTP('foo')
you declare ftp_client as a global variable. This means it lives at the module level (where your classes are for example).
The second line is wrong. You wanted to assign to the global variable but instead you set an instance attribute of the same name.
It should be:
global ftp_client
ftp_client = ftplib.FTP('foo')
But let me suggest a different approach. A common practice is to put such stuff inside the class, since it is shared by all instances of this class.
class FtpFileCommand(sublime_plugin.TextCommand):
ftp_client = None
def run(self, args):
FtpFileCommand.ftp_client = ftplib.FTP('foo')
# login and stuff
Notice that the method doesn't use self so it might as well be a class method:
class FtpFileCommand(sublime_plugin.TextCommand):
ftp_client = None
#classmethod
def run(cls, args):
cls.ftp_client = ftplib.FTP('foo')
# login and stuff
This way you will get the class as the first argument and you can use it to access the FTP client without using the class name.
If there's only a single shared variable, then a global is the simplest solution. But note that a variable only needs to be declared with global when it is being assigned to. If the global variable is an object, you can call its methods, modify its attributes, etc without declaring it as global first.
An alternative to using global variables is to use class attributes which are accessed using classmethods. For example:
class FtpFile(object):
_client = None
#classmethod
def client(cls):
return cls._client
#classmethod
def setClient(cls, client):
cls._client = client
class FtpFileCommand(FtpFile, sublime_plugin.TextCommand):
def run(self, args):
client = self.client()
class FtpFileEventListener(FtpFile, sublime_plugin.EventListener):
def run(self, args):
client = self.client()
Could you add a constructor to each class then pass ftp_client as an argument?
class FtpFileCommand(sublime_plugin.TextCommand):
...
def __init__(self, ftp_client):
self.ftp_client = ftp_client
...
class FtpFileEventListener(sublime_plugin.EventListener):
...
def __init__(self, ftp_client):
self.ftp_client = ftp_client
...
Yak... THANK YOU SO MUCH FOR THIS!!!
You declare ftp_client as a global variable. This means it lives at
the module level (where your classes are for example).
I was having a difficult time trying to write my program "properly" where I'm utilizing classes and functions and couldn't call any of the variables. I recognized that global would make it available outside of the class. When I read that I thought... If it lives outside of the class then the variable I need to retrieve from the py script that I'm importing that module from would be:
module.variable
And then within that module, I declared another global variable to call it from the main script... so example...
#Main Script main.py
import moduleA
print(moduleA.moduleA.variable)
#ModuleA code moduleA.py
import moduleB
class classA():
def functionA():
global moduleA_variable
call.something.from.moduleB.classB.functionB()
moduleA_variable = moduleB.moduleB_variable
ModuleB code moduleB.py
class classB():
def functionB():
global moduleB_variable
moduleB_variable = retrieve.tacos()
I hope my explanation also helps someone. I'm a beginner with python and struggled with this for a while. In case it wasn't clear... I had separate custom modules made up of a few different .py files. Main was calling moduleA and moduleA was calling moduleB. I had to return the variable up the chain to the main script. The point of me doing it this way, was to keep the main script clean for the most part, and set myself up for executing repetitive tasks without having to write pages of crap. Basically trying to reuse functions instead of writing a book.

Categories

Resources