5

Look at this code:

class MyClass():

    # Why does this give me "NameError: name 'self' is not defined":
    mySelf = self

    # But this does not?
    def myFunction(self):
        mySelf2 = self

Basically I want a way for a class to refer to itself without needing to name itself specifically, hence I want self to work for the class, not just methods/functions. How can I achieve this?

EDIT: The point of this is that I'm trying to refer to the class name from inside the class itself with something like self.class._name_ so that the class name isn't hardcoded anywhere in the class's code, and thus it's easier to re-use the code.

EDIT 2: From what I've learned from the answers below, what I'm trying to do is impossible. I'll have to find a different way. Mission abandoned.

EDIT 3: Here is specifically what I'm trying to do:

class simpleObject(object):
    def __init__(self, request):
        self.request = request

@view_defaults(renderer='string')
class Test(simpleObject):

    # this line throws an error because of self
    myClassName = self.__class__.__name__

    @view_config(route_name=myClassName)
    def activateTheView(self):
        db = self.request.db
        foo = 'bar'

        return foo
zakdances
  • 22,285
  • 32
  • 102
  • 173

6 Answers6

6

Note that self is not defined at the time when you want the class to refer to itself for the assignment to work. This is because (in addition to being named arbitrarily), self refers to instances and not classes. At the time that the suspect line of code attempts to run, there is as of yet no class for it to refer to. Not that it would refer to the class if there was.

In a method, you can always use type(self). That will get the subclass of MyClass that created the current instance. If you want to hard-code to MyClass, that name will be available in the global scope of the methods. This will allow you to do everything that your example would allow if it actually worked. E.g, you can just do MyClass.some_attribute inside your methods.

You probably want to modify the class attributes after class creation. This can be done with decorators or on an ad-hoc basis. Metaclasses may be a better fit. Without knowing what you actually want to do though, it's impossible to say.

UPDATE:

Here's some code to do what you want. It uses a metaclass AutoViewConfigMeta and a new decorator to mark the methods that you want view_config applied to. I spoofed the view_config decorator. It prints out the class name when it's called though to prove that it has access to it. The metaclass __new__ just loops through the class dictionary and looks for methods that were marked by the auto_view_config decorator. It cleans off the mark and applies the view_config decorator with the appropriate class name.

Here's the code.

# This just spoofs the view_config decorator.
def view_config(route=''):
    def dec(f):
        def wrapper(*args, **kwargs):
            print "route={0}".format(route)
            return f(*args, **kwargs)
        return wrapper
    return dec

# Apply this decorator to methods for which you want to call view_config with 
# the class name. It will tag them. The metaclass will apply view_config once it 
# has the class name. 
def auto_view_config(f):
    f.auto_view_config = True
    return f

class AutoViewConfigMeta(type):
    def __new__(mcls, name, bases, dict_):
        #This is called during class creation. _dict is the namespace of the class and
        # name is it's name. So the idea is to pull out the methods that need
        # view_config applied to them and manually apply them with the class name.
        # We'll recognize them because they will have the auto_view_config attribute
        # set on them by the `auto_view_config` decorator. Then use type to create
        # the class and return it.

        for item in dict_:
            if hasattr(dict_[item], 'auto_view_config'):  
                method = dict_[item]
                del method.auto_view_config # Clean up after ourselves.
                # The next line is the manual form of applying a decorator.
                dict_[item] = view_config(route=name)(method)  

        # Call out to type to actually create the class with the modified dict.
        return type.__new__(mcls, name, bases, dict_)


class simpleObject(object):
    __metaclass__ = AutoViewConfigMeta 


class Test(simpleObject):

    @auto_view_config
    def activateTheView(self):
        foo = 'bar'

        print foo

if __name__=='__main__':
    t = Test()
    t.activateTheView()

Let me know if you have any questions.

aaronasterling
  • 68,820
  • 20
  • 127
  • 125
  • I want to get the class name from inside the class with something like self.__class__.__name__ – zakdances Apr 03 '12 at 04:29
  • @yourfriendzak, you can do that in methods with `type(self).__name__`. If you want it to be a class attribute, then it already is _after_ class creation, i.e., it's the `__class__` class attribute. If you don't want to get the name of the current subclass, then just hard-code it in but then what's the point? – aaronasterling Apr 03 '12 at 04:31
  • I hear you, but what I'm trying to do is call type(self).__name__ OUTSIDE of a method. I want type(self).__name__ as a class attribute WITHOUT having to create an instance of that class first, which is apparently impossible. – zakdances Apr 03 '12 at 04:38
  • @yourfriendzak. Why do you want `MyClass` to have an additional class attribute that refers to its name? It already has the `__name__` attribute. Why doesn't that suffice? – aaronasterling Apr 03 '12 at 04:42
  • how do I refer to the __name__ attribute if I don't have a "self" (self.__name__ throws an error)? I want a way I don't have to hardcode the class name inside of the class itself so I can re-use the code easily. – zakdances Apr 03 '12 at 04:43
  • @yourfriendzak From where do you want to access the class name? – aaronasterling Apr 03 '12 at 04:46
  • From a place similar to where it says "mySelf = self" in my above example. By the way, `__name__` doesn't throw an error but `__class__` does. `__name__` also doesn't seem to return the correct class name. – zakdances Apr 03 '12 at 04:49
  • @yourfriendzak. That's not possible. The class isn't defined at that point. You're going to need to use decorators or metaclasses or something. Why do you want to do this? Without knowing I can't say much more. Perhaps you should edit your question with more details. – aaronasterling Apr 03 '12 at 04:51
  • @yourfriendzak the reason that `__name__` is defined is that it's a magic variable that will take the name of the module. The class attribute that points to the name happens to have the same name but will always be accessed as an attribute so there's no risk of confusion (for someone that understands python) – aaronasterling Apr 03 '12 at 04:53
  • I added some additional info to my edit to try to make it more clear what I want. – zakdances Apr 03 '12 at 04:53
  • @yourfriendzak, I still don't know why you can't just use `type(self).__name__`. Your edit doesn't clear anything up. Do you only want the name to be available inside the methods? – aaronasterling Apr 03 '12 at 04:54
  • type(self) throws an error because self is not defined. I want the class name available as a class variable. – zakdances Apr 03 '12 at 04:55
  • @yourfriendzak. It __wont__ throw an error __if__ you do it from __inside__ methods. There is no way to get the name of the class __before__ it is created without using metaclasses or decorators. __After__ the class is defined, it __already__ has the `__name__` attribute which has exactly what you want. So I still don't know what you're trying to do. – aaronasterling Apr 03 '12 at 04:58
  • I don't know how to make my intentions any more clear, but "There is no way to get the name of the class before it is created without using metaclasses or decorators." answers my question. Thanks for taking the time. Btw, do you know how to declare a class variable from inside an `__init__` method? – zakdances Apr 03 '12 at 05:00
  • @yourfriendzak To assign to a class variable from inside any method (`__init__` included), just do `type(self).my_attr = my_value`. This is fairly dubious though as it will run on every instantiation. Perhaps you'd like to guard it with a check like `if not hasattr(type(self), 'my_attr'):` – aaronasterling Apr 03 '12 at 05:08
1

Python has an "explict is better than implicit" design philosophy.

Many languages have an implicit pointer or variable in the scope of a method that (e.g. this in C++) that refers to the object through which the method was invoked. Python does not have this. Here, all bound methods will have an extra first argument that is the object through which the method was invoked. You can call it anything you want (self is not a keyword like this in C++). The name self is convention rather than a syntactic rule.

Your method myFunction defines the variable self as a parameter so it works. There's no such variable at the class level so it's erroring out.

So much for the explanation. I'm not aware of a straightforward way for you to do what you want and I've never seen such requirement in Python. Can you detail why you want to do such a thing? Perhaps there's an assumption that you're making which can be handled in another way using Python.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
  • I'm trying to define a top-level class "template" that I can re-use. I have a decorator in the class definition like so @view_config(route_name='myClass') I want to be able to not have to use the myClass word so that value is automatically mapped to the name of the class which that @view_config is in – zakdances Apr 03 '12 at 04:26
  • I'm not exactly sure how you can do this. However, it sounds like you want to create attributes inside the class depending on runtime parameters. Perhaps a metaclass or some kind of factory to create classes would be better than a "template" from which you subclass others. – Noufal Ibrahim Apr 03 '12 at 04:36
  • @yourfriendzak Please update the answer with info about this decorator and what it does. That's closer to what you want to achieve. – bereal Apr 03 '12 at 04:59
1

self is just a name, your self in this case is a class variable and not this for the object using which it is called,

self is treated as a normal variable and it is not defined, where as the self in the function comes from the object used for calling.

you want to treat the object reference in self as a class variable which is not possible.

avasal
  • 14,350
  • 4
  • 31
  • 47
0

self isn't a keyword, it's just a convention. The methods are attributes of the class object (not the instance), but they receive the instance as their first argument. You could rename the argument to xyzzy if you wanted and it would still work the same way.

But (as should be obvious) you can't refer to a method argument outside the body of the method. Inside a class block but outside of any method, self is undefined. And the concept wouldn't even make sense -- at the time the class block is being evaluated, no instance of the class can possibly exist yet.

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
  • My problem is not with the specific word 'self' (I know that it's arbitrary). The problem is that I want to refer to an instance in the class itself (usually represented by the word 'self') without having to use it in a specifically defined function. – zakdances Apr 03 '12 at 04:22
  • @yourfriendzak: See my edit. I think you're misunderstanding how the `class` keyword works. The body of the `class` block is evaluated to form the `__dict__` of the class attributes. In Python, a class is just an object like any other, except that it implements the `__call__` special such that calling the class object returns a new instance of that class. In the context of the `class` block there simply isn't any instance you could refer to, even if `self` were available. – Daniel Pryden Apr 03 '12 at 04:27
0

Because the name self is explicitly defined as part of the arguments to myFunction. The first argument to a method is the instance that the method was called on; in the class body, there isn't an "instance we're dealing with", because the class body deals with every possible instance of the class (including ones that don't necessarily exist yet) - so, there isn't a particular object that could be called self.

If you want to refer to the class itself, rather than some instance of it, this is spelled self.__class__ (or, for new-style classes in Py2 and all classes in Py3, type(self)) anywhere self exists. If you want to be able to deal with this in situations where self doesn't exist, then you may want to look at class methods which aren't associated with any particular instance, and so take the class itself in place of self. If you really need to do this in the class body (and, you probably don't), you'll just have to call it by name.

lvc
  • 34,233
  • 10
  • 73
  • 98
0

You can't refer to the class itself within the class body because the class doesn't exist at the time that the class body is executed. (If the previous sentence is confusing, reading up about metaclasses will either clear this up or make you more confused.)

Within an instance method, you can refer to the class of the instance with self.__class__, but be careful here. This will be the instance's actual class, which through the power of inheritance might not be the class in which the method was defined.

Within a class method, the class is passed in as the first argument, much like instances are the first argument to instance methods:

class MyClass(object):
    @classmethod
    def foo(cls):
        print cls.__name__

MyClass.foo() # Should print "MyClass"

As with instance methods, the actual class might differ due to inheritance.

class OtherClass(MyClass): 
    pass

OtherClass.foo() # Should print "OtherClass"

If you really need to refer to MyClass within a method of MyClass, you're pretty much going to have to refer to it as MyClass unless you use magic. This sort of magic is more trouble than it is worth.

kenm
  • 23,127
  • 2
  • 43
  • 62