Python: Reference to a class from a string? - python

How to use a string containing a class name to reference a class itself?
See this (not working) exemple...
class WrapperClass:
def display_var(self):
#FIXME: self.__class_name__.__name__ is a string
print self.__class__.__name__.the_var
class SomeSubClass(WrapperClass):
var = "abc"
class AnotherSubClass(WrapperClass):
var = "def"
And an obvious error message:
>>> b = SomeSubClass()
>>> b.display_var()
Traceback (most recent call last):
File "", line 1, in
File "", line 4, in display_var
AttributeError: 'str' object has no attribute 'the_var'
>>>
Thanks!

How to use a string containing a class name to reference a class itself?
Classes aren't special, they're just values contained in variables. If you've said:
class X(object): pass
in global scope, then the variable ‘X’ will be a reference to the class object.
You can get the current script/module's global variables as a dictionary using ‘globals()’, so:
classobj= globals()[self.__class__.__name__]
print classobj.var
(locals() is also available for local variables; between them you shouldn't ever need to use the awful eval() to access variables.)
However as David notes, self.__class__ is already the classobj, so there's no need to go running about fetching it from the global variables by name; self.__class__.var is fine. Although really:
print self.var
would be the usual simple way to do it. Class members are available as members of their instances, as long as the instance doesn't overwrite the name with something else.

Depending on where you get this string, any general method may be insecure (one such method is to simply use eval(string). The best method is to define a dict mapping names to classes:
class WrapperClass:
def display_var(self):
#FIXME: self.__class_name__.__name__ is a string
print d[self.__class__.__name__].the_var
class SomeSubClass(WrapperClass):
the_var = "abc"
class AnotherSubClass(WrapperClass):
the_var = "def"
d = {'WrapperClass': WrapperClass, 'SomeSubClass': SomeSubClass, 'AnotherSubClass': AnotherSubClass}
AnotherSubClass().display_var()
# prints 'def'

Your example would work if you called print self.__class__.var. I don't think there's any need to use the name.

There exists a case where one has the name of a class, but not a reference to it. A tkinter Entry widget has a validate method which returns to the callback function (%W parameter) the name of the widget, not a reference to it. If you have a window with an array of entry fields, It is inconvenient to use a different callback function for each entry. Converting the string name to the reference in the callback function is a more efficient way to associate the callback to the source of the validate event. I would have commented on Devin's answer, but don't have the reputation points to make comments yet.

Related

What is the use of class attribute which is a method/function

In Python when we define class all its members including variables and methods also becomes attributes of that class. In following example MyClass1.a and MyClass1.mydef1 are attributes of class MyClass1.
class MyClass1:
a = 10
def mydef1(self):
return 0
ins1 = MyClass1() # create instance
print(MyClass1.a) # access class attribute which is class variable
print(MyClass1.mydef1) # No idea what to do with it so just printing
print(ins1.mydef1) # No idea what to do with it so just printing
Output
10
<function MyClass1.mydef1 at 0x0000000002122EA0>
<bound method MyClass1.mydef1 of <__main__.MyClass1 object at 0x000000000212D0F0>>
Here attribute a is a variable and it can be used like any other variable.
But mydef1 is a method, if it is not invoked and just used like MyClass1.mydef1 or ins1.mydef1, it returns object for that method(correct me if I am wrong).
So my question is, what can we do with the Class/instance methods without invoking it? Are there any use cases for it or is it just good to know thing?
An attribute of a class that happens to be a function becomes a method for instances or that class:
inst.foo(params, ...)
is internally translated into:
cls.foo(inst, params, ...)
That means that what is actually invoked is the attribute from the class of the instance, and the instance itself is prepended to the argument list. It is just Python syntax to invoke methods on objects.
In your example the correct uses would be:
print(MyClass1.mydef1(ins1)) # prints 0
print(ins1.mydef1()) # also prints 0
Well instance methods can be called with the appropriate parameters of course:
print(ins1.mydef1()) # no parameters, so empty parenthesis, this call should print "0" in your example instead of the method description
If you use it without the parenthesis, you are playing with reference to the function, I don't think you can have any use of it, except checking the list of methods available in a class or something like that.

How to get the name of an object from a class in Python? [duplicate]

This question already has answers here:
How to convert variable into string in python
(9 answers)
Getting an instance name inside class __init__() [duplicate]
(10 answers)
Closed 6 years ago.
I know this is a weird idea. The idea would be something like this:
class AnyClass:
def __init__(self):
# print object name
Then create a new object
test = AnyClass()
And finally get this output:
'test'
That is not the idea behind this, but is an easy example of what I'm trying to...
PS: I'm not trying to get the class name, just the object name (if possible)
PS2: I know I can get the name with test.__name__ but I'm trying to get the name inside the class, not outside.
Consider this:
>>> a = dict()
>>> b = a
Both a and b reference the exact same object.
>>> a is b
True
When you do a . operation on an object, you're looking up an attribute on that object. An object can be referenced in many different locations; it makes no sense for it to store all those reference names, especially when those names are only bound within certain contexts. For example
def generator():
a = dict()
yield a
b = next(generator())
Both a and b refer to the same dict object, but you can't use a to reference the dict anywhere else besides in the generator function.
Within a specific context, you can test the bound names and see if they refer to a specific object.
test = MyObject()
for name, obj in locals().items():
if test is obj:
print name
First: you don't want to do this, there is no reason to do this, and if you think you need to do this, you're wrong.
Second: you can't do it in the __init__ method because the name reference test referring to the new AnyClass instance object hasn't been added to the memory space ("bound") yet. However, you could do it like this.
class AnyClass():
def echo_name(self):
{v:k for k,v in locals().items()}[self]
test = AnyClass()
test.echo_name()
This will return the first variable encountered in the locals() dictionary that is assigned to the test object. There is no guarantee for the order in which those variables will be returned.
To explain a bit further about why it won't work in the __init__ method, when you do this:
test = AnyClass()
A new instance of AnyClassis constructed according to the instructions of the class definition (including the definitions of any parent or metaclass). This construction happens in phases, the last phase of which is executing the __init__ method. Prior to __init__, other methods that will be executed, if they exist, are __new__, and also the the __new__, __init__, and __call__ methods of the metaclass (if one exists).
So at the point in time the code in the body of the __init__ method is being executed, the object is still being constructed. Therefore there is, as of yet, nothing in the locals() dictionary assigned to the name 'test'. There is only a member called 'self'. And, obviously, if you reverse-lookup the self object in the locals() dictionary looking for a registered name, the name you will get is the name 'self'. Which... isn't useful.

Can't view variables within a static method

EDIT:
Ok so here is the background. I am trying to understand code written by a coworker. He has specifically written the code in the format of this example:
>>> class A:
#staticmethod
def ok(abc):
thebigone=abc
(This is a simplification but the style is the same. Namely, a variable was declared in a #staticmethod within a class)
So since I am new to his code, I wanted to see what type of data thebigone was.I called the function in the shell and tried to use the to return the contents of this variable. I ran the function ok and then tried to use the shell to print the contents of the variable thebigone but the shell returned a definition error.
Here are the commands I tried in the shell:
>>> class A:
#staticmethod
def ok(abc):
thebigone=abc
>>> A.ok('d')
>>> thebigone
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
thebigone
NameError: name 'thebigone' is not defined
>>> A.thebigone
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
A.thebigone
AttributeError: type object 'A' has no attribute 'thebigone'
After running the function, is it possible for the shell to return the contents of the variable, thebigone without altering the code? If not why is that?
Thanks
You can't create global variables spontaneously inside a method any more than you can create them spontaneously inside a function. Otherwise, you wouldn't be able to have local variables in a static method without polluting the global namespace.
In addition to Pynchia's solution, you can declare a global variable outside the class, and reference it explicitly with global:
THEBIGONE = None
class a:
#staticmethod
def ok(abc):
global THEBIGONE
THEBIGONE = abc
Or you might want to use a classmethod to make it a member of the class:
class a:
#classmethod
def ok(cls, abc):
cls.THEBIGONE = abc
Class methods are generally more useful than static methods, so consider whether that might be a better solution to your real problem.
as it is assigned, THEBIGONE is a variable (name) in the local namespace of the method, not of the class.
Try with
a.THEBIGONE = ...
Generally speaking, in Python where the assignment takes places defines the namespace where the name ends up.
So the assignment THEBIGONE = ... makes it go in the current namespace, i.e. the method's.
Unless, you explicitly specify where the name should go, e.g.
an object (usually called self in instance methods) with self.THEBIGONE = ...
a class, with a.THEBIGONE = ... in your case. Note that, as suggested in trentcl's answer, you could make the method a classmethod and avoid using the class' name explicitly.
etc.
BTW: class names should start with capital letters, using the CapWords convention, leave lowercase to variables.
Please see the guidelines described in Python's PEP-8

Using globals() to create class object

I'm new in programming so please don't kill me for asking stupid questions.
I've been trying to understand all that class business in Python and I got to the point where could not find answer for my question just by google it.
In my program I need to call a class from within other class based on string returned by function. I found two solutions: one by using getattr() and second one by using globals() / locals().
Decided to go for second solution and got it working but I'm really don't understand how it's working.
So there is the code example:
class Test(object):
def __init__(self):
print "WORKS!"
room = globals()['Test']
room()
type(room()) gives:
<class '__main__.Test'>
type(room) gives:
<type 'type'> # What????
It looks like room() is a class object, but shouldn't that be room instead of room()?
Please help me because it is a little bit silly if I write a code which I don't understand myself.
What happens here is the following:
class Test(object):
def __init__(self):
print "WORKS!"
room = globals()['Test']
Here you got Test as room the way you wanted. Verify this:
room is Test
should give True.
type(room()) gives:
<class '__main__.Test'>
You do one step an go it backwards: room() returns the same as Test() would - an instance of that class. type() "undoes" this step resp. gets the type of the object - this is, of course, Test.
type(room) gives:
<type 'type'> # What????
Of course - it is the type of a (new style) class. The same as type(Test).
Be aware, however, that for
In my program I need to call a class from within other class based on string returned by function. I found two solutions: one by using getattr() and second one by using globals() / locals().
it could be better to create an explicitly separate dict. Here you have full control over which objects/classes/... are allowed in that context and which are not.
First of all, I'd go with getattr instead.
In your example, room equals Test and is a class. Its type is type.
When you call room(), you instantiate Test, so room() evaluates to an instance of Test, whose type is Test.
Classes are objects too, in Python. All this does:
class Test(object):
def __init__(self):
print "WORKS!"
is create a class object and bind it to the name Test. Much as this:
x = []
creates a list object and binds it to the name x.
Test() isn't magic syntax for creating an instance. The Test is perfectly ordinary variable lookup, and the () is perfectly ordinary "call with empty arguments". It just so happens that calling a class will create an instance of that class.
If follows then that your problem of instantiating a class chosen based on having the name of the class as a string boils down to the much simpler problem of finding an object stored in a variable. It's exactly the same problem as getting that list bound to the name x, given the string "x". Once you've got a reference to the class in any old variable, you can simply call it to create your instance.
globals() returns a dictionary mapping the names of globals to their values. So globals()['Test'] will get you the class Test just as easily as globals()['x'] will get you the list. However it's usually not considered great style to use globals() like this; your module probably contains a large number of callables (including a bunch imported from other modules) that you don't want to be accidentally invoked if the function can be made to return their name. Given that classes are just ordinary objects, you can put them in a dictionary of your own making:
classes = {
'Test': Test,
'SomethingElse': Something,
...
}
This involves a bit more typing, but it's also easier to see what the intended usage is, and it gives you a bit more flexibility, since you can also easily pass this dictionary to other modules and have the instantiation take place elsewhere (you could do that with globals(), but then you're getting very weird).
Now, for the type(room) being type. Again, this is just a simple consequence of the fact that classes themselves are also objects. If a class is an object, then it should also be an instance of some class. What class is that? type, the "type of types". Much as any class defines the common behaviour of all its instances, the class type defines the common behaviour of all classes.
And just to make your brain hurt, type is an instance of itself (since type is also a class, and type is the class of classes). And it's a subclass of object (since all type instances are object instances, but not all object instances are type instances), and also an instance of object (since object is the root class of which everything is an instance).
You can generally ignore type as an advanced topic, however. :)

Python Variable Declaration

I want to clarify how variables are declared in Python.
I have seen variable declaration as
class writer:
path = ""
sometimes, there is no explicit declaration but just initialization using __init__:
def __init__(self, name):
self.name = name
I understand the purpose of __init__, but is it advisable to declare variable in any other functions?
How can I create a variable to hold a custom type?
class writer:
path = "" # string value
customObj = ??
Okay, first things first.
There is no such thing as "variable declaration" or "variable initialization" in Python.
There is simply what we call "assignment", but should probably just call "naming".
Assignment means "this name on the left-hand side now refers to the result of evaluating the right-hand side, regardless of what it referred to before (if anything)".
foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication
As such, Python's names (a better term than "variables", arguably) don't have associated types; the values do. You can re-apply the same name to anything regardless of its type, but the thing still has behaviour that's dependent upon its type. The name is simply a way to refer to the value (object). This answers your second question: You don't create variables to hold a custom type. You don't create variables to hold any particular type. You don't "create" variables at all. You give names to objects.
Second point: Python follows a very simple rule when it comes to classes, that is actually much more consistent than what languages like Java, C++ and C# do: everything declared inside the class block is part of the class. So, functions (def) written here are methods, i.e. part of the class object (not stored on a per-instance basis), just like in Java, C++ and C#; but other names here are also part of the class. Again, the names are just names, and they don't have associated types, and functions are objects too in Python. Thus:
class Example:
data = 42
def method(self): pass
Classes are objects too, in Python.
So now we have created an object named Example, which represents the class of all things that are Examples. This object has two user-supplied attributes (In C++, "members"; in C#, "fields or properties or methods"; in Java, "fields or methods"). One of them is named data, and it stores the integer value 42. The other is named method, and it stores a function object. (There are several more attributes that Python adds automatically.)
These attributes still aren't really part of the object, though. Fundamentally, an object is just a bundle of more names (the attribute names), until you get down to things that can't be divided up any more. Thus, values can be shared between different instances of a class, or even between objects of different classes, if you deliberately set that up.
Let's create an instance:
x = Example()
Now we have a separate object named x, which is an instance of Example. The data and method are not actually part of the object, but we can still look them up via x because of some magic that Python does behind the scenes. When we look up method, in particular, we will instead get a "bound method" (when we call it, x gets passed automatically as the self parameter, which cannot happen if we look up Example.method directly).
What happens when we try to use x.data?
When we examine it, it's looked up in the object first. If it's not found in the object, Python looks in the class.
However, when we assign to x.data, Python will create an attribute on the object. It will not replace the class' attribute.
This allows us to do object initialization. Python will automatically call the class' __init__ method on new instances when they are created, if present. In this method, we can simply assign to attributes to set initial values for that attribute on each object:
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before
Now we must specify a name when we create an Example, and each instance has its own name. Python will ignore the class attribute Example.name whenever we look up the .name of an instance, because the instance's attribute will be found first.
One last caveat: modification (mutation) and assignment are different things!
In Python, strings are immutable. They cannot be modified. When you do:
a = 'hi '
b = a
a += 'mom'
You do not change the original 'hi ' string. That is impossible in Python. Instead, you create a new string 'hi mom', and cause a to stop being a name for 'hi ', and start being a name for 'hi mom' instead. We made b a name for 'hi ' as well, and after re-applying the a name, b is still a name for 'hi ', because 'hi ' still exists and has not been changed.
But lists can be changed:
a = [1, 2, 3]
b = a
a += [4]
Now b is [1, 2, 3, 4] as well, because we made b a name for the same thing that a named, and then we changed that thing. We did not create a new list for a to name, because Python simply treats += differently for lists.
This matters for objects because if you had a list as a class attribute, and used an instance to modify the list, then the change would be "seen" in all other instances. This is because (a) the data is actually part of the class object, and not any instance object; (b) because you were modifying the list and not doing a simple assignment, you did not create a new instance attribute hiding the class attribute.
This might be 6 years late, but in Python 3.5 and above, you can give a hint about a variable type like this:
variable_name: type_name
or this:
variable_name # type: shinyType
This hint has no effect in the core Python interpreter, but many tools will use it to aid the programmer in writing correct code.
So in your case(if you have a CustomObject class defined), you can do:
customObj: CustomObject
See this or that for more info.
There's no need to declare new variables in Python. If we're talking about variables in functions or modules, no declaration is needed. Just assign a value to a name where you need it: mymagic = "Magic". Variables in Python can hold values of any type, and you can't restrict that.
Your question specifically asks about classes, objects and instance variables though. The idiomatic way to create instance variables is in the __init__ method and nowhere else — while you could create new instance variables in other methods, or even in unrelated code, it's just a bad idea. It'll make your code hard to reason about or to maintain.
So for example:
class Thing(object):
def __init__(self, magic):
self.magic = magic
Easy. Now instances of this class have a magic attribute:
thingo = Thing("More magic")
# thingo.magic is now "More magic"
Creating variables in the namespace of the class itself leads to different behaviour altogether. It is functionally different, and you should only do it if you have a specific reason to. For example:
class Thing(object):
magic = "Magic"
def __init__(self):
pass
Now try:
thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1
Or:
class Thing(object):
magic = ["More", "magic"]
def __init__(self):
pass
thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]
This is because the namespace of the class itself is different to the namespace of the objects created from it. I'll leave it to you to research that a bit more.
The take-home message is that idiomatic Python is to (a) initialise object attributes in your __init__ method, and (b) document the behaviour of your class as needed. You don't need to go to the trouble of full-blown Sphinx-level documentation for everything you ever write, but at least some comments about whatever details you or someone else might need to pick it up.
For scoping purpose, I use:
custom_object = None
Variables have scope, so yes it is appropriate to have variables that are specific to your function. You don't always have to be explicit about their definition; usually you can just use them. Only if you want to do something specific to the type of the variable, like append for a list, do you need to define them before you start using them. Typical example of this.
list = []
for i in stuff:
list.append(i)
By the way, this is not really a good way to setup the list. It would be better to say:
list = [i for i in stuff] # list comprehension
...but I digress.
Your other question.
The custom object should be a class itself.
class CustomObject(): # always capitalize the class name...this is not syntax, just style.
pass
customObj = CustomObject()
As of Python 3, you can explicitly declare variables by type.
For instance, to declare an integer one can do it as follows:
x: int = 3
or:
def f(x: int):
return x
see this question for more detailed info about it:
Explicitly declaring a variable type in Python

Categories