Python class variable name vs __name__ - python

I'm trying to understand the relationship between the variable a Python class object is assigned to and the __name__ attribute for that class object. For example:
In [1]: class Foo(object):
...: pass
...:
In [2]: Foo.__name__ = 'Bar'
In [3]: Foo.__name__
Out[3]: 'Bar'
In [4]: Foo
Out[4]: __main__.Bar
In [5]: Bar
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-5-962d3beb4fd6> in <module>()
----> 1 Bar
NameError: name 'Bar' is not defined
So it seems like I have changed the __name__ attribute of the class but I can't refer to it by that name. I know this is a bit general but could someone explain the relationship between Foo and Foo.__name__?

It's simple. There is no relationship at all.
When you create a class a local variable is created with name you used, pointing at the class so you can use it.
The class also gets an attribute __name__ that contains the name of that variable, because that's handy in certain cases, like pickling.
You can set the local variable to something else, or change the __name__ variable, but then things like pickling won't work, so don't do that.

__name__ is mere self-identification, in oder to know what type an instance of it really is.
The other thing is the way it can be accessed with. That can vary if you re-assign it.
They both are assigned at the time you define the class.
It works the same way with functions: if you def them, they get assigned to the given name and they get the respective __name__ attribute.
OTOH, if you have a lambda function, it gets a __name__ attribute of <lambda>, because it doesn't know the name it gets assigned to.

Short version
class Foo(object): pass creates a class and assigns it to local name Foo.
Foo.__name__ = 'Bar' assigns a new value to attribute __name__. The enclosing scope is not affected.
Long version
The class statement creates a class and assigns to the name provided in the local scope. When creating a class Python tells the class the name it was created with by assigning it to the class's __name__ attribute.
Assigning to a class's attribute does not introduce a name into the local scope. Therefore any changes to attributes (such as __name__) do not affect the enclosing scope.

You need to keep in mind that in python a class is just an object like any other. It wouldn't make sense for an object to contain an attribute that was linked to a variable that refers to the object, because there could be any number of variable names referring to it. Any time you write an assignment (Bar = Foo) or pass the object to a function, you have a new reference. Naturally all objects must be independent of how they are referenced.
__name__ is simply a piece of information attached to the class object, which happens to be the same as the variable name it's initially assigned to.

Related

Python self.variable vs private member instance variable

I just started programming in Python, and there's something OOP-related that I'm not quite clear on. So in Python, you can create and assign value to a new variable without needing to first declare it. So with that, is there any difference between creating and assigning a new variable for self (eg. self.variable = 5) inside a function (eg. __init__()) vs. creating and assigning a new private member variable? It seems to me like there is no difference at all.
class Foo:
__var_A = 5;
def __init__(self):
self.__var_B = 5;
self.printVars()
def printVars(self):
print(self.__var_A)
print(self.__var_B)
foo = Foo()
There is in fact a difference between those two variables:
Since __var_A is defined in class Foo instead of an individual member-function like __init__, you can change it for all instances at once like this:
Foo._Foo__var_A = 2
This will not work for __var_B since you define it individually per instance.
Note though, that changing __var_A on an instance will not change it for everyone else, it will instead put a local override into the object itself:
foo2 = Foo()
foo2._Foo__var_A = 1
Foo._Foo__var_A = 2
(foo2._Foo__var_A, foo._Foo__var_A) # Returns: (1, 2)
It seems to me like there is no difference at all.
That is correct.
But remember that Python does not have 'private' members. That is only a convention.
The difference between protected and public is a matter of convention. And class or member variable prefixed by one _ indicates to a developer "don't use this unless you know what you're doing." Private is a SLIGHTLY different case, however: they require two _ and they cannot be suffixed by more than one _. Here are the docs:
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.
Name mangling is an important part of Python inheritence. It allows classes to protect API calls from accidental manipulation of descendants (see above docs). However, if necessary you can still access them via _<class-name><var name>. Eg:
class Foo:
def __init__(self):
self.__bar = 1
print(Foo()._Foo__bar)
# 1
There is no difference if the variable is declared under class foo: of within the __init__(self). Both methods accomplish the same thing.
However, this is slight a twist if the variable (e.g. self.bar) is declared from a method other than __init__. Using
def bar(self):
self.bar = 'test'
creates a variable within the object that is not part of the default class. You can do this, but it is not good programming practice for python.
There is a difference. Consider following example:
foo = Foo()
foo.__dict__
This will return:
{'_Foo__var_B': 5}
But, following code:
bar = Foo
bar.__dict__
will return
{'_Foo__var_A': 5,
'__doc__': None,
'__init__': <function __main__.__init__>,
'__module__': '__main__',
'printVars': <function __main__.printVars>}
This leads to conclusion that __var_A will be accessible even if Foo is not instantiated, while __var_B will not be.

Do class/static variables have access to static methods?

Forgive me if this question is obvious, but from what I've read on Python's OOP tutorials none of them mention how to have a static variable store a static method. In my code I tried:
class Features:
a_static_variable = 1
a_static_variable_that_references_a_static_function = Features.func1
#staticmethod
def func1(blah):
print(blah)
When trying to run this I received:
NameError: name 'Features' is not defined
Is it possible for a class method to reference a static method in its own class? If so, how do I do this. I tried replacing Features with nothing and self but as I expected those made no sense as well.
This is simply a case of func1 not being defined yet.
It should work if you reorder:
class Features:
a_static_variable = 1
#staticmethod
def func1(blah):
print(blah)
a_static_variable_that_references_a_static_function = func1
Yes, just define the function first:
class Features:
#staticmethod
def func1(blah):
print(blah)
a_static_variable = 1
a_static_variable_that_references_a_static_function = func1
Features.a_static_variable_that_references_a_static_function('test')
Your code has two errors (explained in the other answers). This example may help you understand what's going on.
class Example:
class_variable = 'class_variable'
#staticmethod
def static_method():
print('static_method')
class_method = static_method
print(locals())
def instance_method(self):
print(instance_method)
print(locals())
When this code is run, without instantiating a member of this class, the output is:
creating the class:
{'class_variable': 'class_variable',
'__module__': '__main__',
'static_method': <staticmethod object at 0x0135E5F0>,
'class_method': <staticmethod object at 0x0135E5F0>
}
So, while creating the class, a scope is created in which all of the names in that dictionary are accessible.
Now let's look at what happens when we do this:
example = Example()
example.instance_method()
Nothing happens when you instantiate an object, but calling instance_method will print the local variable(s) accessible to that scope.
instance_method
{'self': <__main__.Example instance at 0x01810210>}
Now, you are probably used to creating instance methods that reference class variables.
def other_instance_method(self):
print(Example.class_variable)
Here, Example is not present in the local scope. In order to find it, the global scope needs to be searched (i.e. globals). Note that instead of explicitly referencing Example, we could access the the class variable from the self object itself.
def other_instance_method(self):
print(self.class_variable)
You can do some testing yourself by printing locals() and globals() from various places to get a grip on how the scope changes.

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

Class name as a variable in python

I was just looking at one question here and the OP was using a same name for class, other things and also for variable. When I was trying to answer it, I became confused myself and thus thought of asking.
For example:
class MyClass:
pass
MyClass=MyClass()
Though, I will never code anything like this. I would like to understand how this will be treated by python interpreter. So my question is, is the variable MyClass I will use will be created first or the other way? Which is, creating an instance of MyClass firstly and assigning it to MyClass variable. I think the latter is correct but if that is the case, how will the following be resolved?
class MyClass:
pass
MyClass=MyClass()
new_class=MyClass()
The right-hand side of the assignment is processed first, so an instance of MyClass is created. But then you reassign the name MyClass to that instance. When you execute
new_class = MyClass()
you should get an error about MyClass not being callable, since that name now refers to an instance of the original class, not the class itself.
class MyClass:
pass
MyClass=MyClass()
In simple terms, the above code does three things (in this order):
Defines the class MyClass.
Creates an instance of MyClass.
Assigns that instance to the variable MyClass.
After the last step, the class MyClass is overwritten and can no longer be used. All you have left is an instance of it contained in the variable MyClass.
Moreover, if you try to call this instance as you would a class, you will get an error:
>>> class MyClass:
... pass
...
>>> MyClass=MyClass()
>>> new_class=MyClass()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'MyClass' object is not callable
>>>
The line:
new_class=MyClass()
in most cases will return an error, saying something like instance not callable.
MyClass now refers to the instance of what MyClass previous held that is a class.
You could make a new instance of former MyClass by:
new_class = MyClass.__class__()
MyClass is just just a variable that points/refers to a particular object. First it was class then it was changed to hold an instance of that class.
Variables are treated as objects in Python. From my understanding, when you assign a new instance of MyClass to an object, python will try to create a reference of the original class to the object and duplicate. However, the namespace of the new object is already used (in the original MyClass), and the duplication will return you an error, so the first code will not work.
For the second piece of code, the final line will not execute due to the same reason of Namespace Duplication. Since the last but one line failed, the proposed reference target is still the original MyClass, which won't work at all.

Getting the identifier name of an instance in python

I haven't found anything. I want to do this without passing the name inside the constructor.
class foo:
pass
something = foo()
I want each instance of foo to be aware of its initial identifier name. In this case the instance of foo() I created should be aware that its identifier is the string "something"
I am working on a small api and this would be a very elegant approach, unfortunately I haven't seen anything like this done.
Thanks,
Even if you could do this—which you can't—it would be an abuse of the language. For the sanity of whoever reads your code, please avoid hidden "magic" behavior. Python programmers would not expect their local variable names to be meaningful and actually be exposed to outside code.
You can't. Creation of an object is totally independent from assigning a reference to that object to some named variable.
foo().doSomething() — an instance of foo is not bound to any name and probably gets garbage collected right after the call.
a[1].moo = foo() — what's the name, again?
a = foo()
b = a # is name of foo 'a' or 'b'? both point to the same instance
a = None # but 'a' is gone, so now the name is 'b'?..
OTOH, passing a name to the constructor is painless:
my_foos = {}
for name in ('a', 'b', 'c'):
my_foos[name] = foo(name)
You may even rudely assign an instance attribute, if you won't change the constructor for some reason:
my_foos = {}
for name in ('a', 'b', 'c'):
a_foo = foo()
a_foo.my_mame = name # here
my_foos[name] = a_foo
And if you're into the dark side, you finally can add your foos to global namespace:
globals().update(my_foos) — now you have global names a, b and c, each referring to an aptly-named foo.
And, for foo's sake, name your classes with a capital initial letter :)
As far as I know, in Python a variable is just a name referring to some object instance. You can have many names pointing to the same instance; the instance is not aware of its names (nor should be, IMHO); the same name can be reused later to point to other instance from a complete different class.
Given the Python data model is hard to see why would be useful for the object to know how it is named in some namespace.
You can store references to your instances in a class variable or another container, but it is not very common in Python - because namespaces are such natural and elegant containers.

Categories