关于python:为什么函数参数外的“self”会给出“未定义”的错误?

Why does “self” outside a function's parameters give a “not defined” error?

查看此代码:

1
2
3
4
5
6
7
8
class MyClass():

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

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

基本上,我想要一种方法让一个类引用它自己,而不需要具体地命名它自己,因此我希望自己为这个类工作,而不仅仅是方法/函数。我怎样才能做到这一点?

编辑:这一点是,我试图从类本身内部引用类名,用self.class.u name,这样类名就不会被硬编码在类代码中的任何地方,从而更容易重用代码。

编辑2:从下面的答案中我学到了什么,我想做的是不可能的。我得换个方法。任务被放弃。

编辑3:我想做的是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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


请注意,当您希望类引用自身以便工作时,没有定义self。这是因为(除了随意命名之外),self指的是实例而不是类。在可疑代码行尝试运行时,到目前为止还没有可供其引用的类。不是说如果有的话,它会指这个班。

在一个方法中,您总是可以使用type(self)。这将得到创建当前实例的MyClass的子类。如果要硬编码到MyClass,该名称将在方法的全局范围内可用。这将允许您执行您的示例实际工作时允许的所有操作。例如,您只需在方法中执行MyClass.some_attribute

您可能希望在类创建之后修改类属性。这可以通过装饰师完成,也可以临时完成。元类可能更适合。但是,如果不知道你到底想做什么,就不可能说出来。

更新:

这里有一些代码可以做你想做的事情。它使用一个元类AutoViewConfigMeta和一个新的修饰器来标记您希望view_config应用到的方法。我欺骗了view_config装饰工。它在调用类名时打印出类名,以证明它有权访问它。元类__new__只是在类字典中循环,查找由auto_view_config修饰器标记的方法。它清除标记,并使用具有适当类名的view_config修饰器。

这是密码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 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()

如果有任何问题,请告诉我。


self只是一个名称,在这种情况下,您的self是一个类变量,而不是用于调用它的对象,

self被视为一个正态变量,它没有被定义,因为函数中的self来自用于调用的对象。

您希望将self中的对象引用视为不可能的类变量。


python有一种"明晰优于含蓄"的设计理念。

许多语言在一个方法的范围内有一个隐式指针或变量(例如,C++中的EDCOX1〔5〕),它引用调用该方法的对象。python没有这个。在这里,所有绑定的方法都将有一个额外的第一个参数,该参数是通过它调用方法的对象。你可以称它为你想要的任何东西(EDCOX1,0)不是一个像ECDOX1,5在C++中的关键字。名称self是惯例而不是句法规则。

方法myFunction将变量self定义为一个参数,因此它可以工作。在类级别没有这样的变量,所以它出错了。

解释得太多了。我不知道有什么简单的方法可以让你做你想做的事情,而且我从来没有在Python中看到过这样的要求。你能详细说明你为什么要做这样的事吗?也许有一个假设,您正在做的,可以用另一种方式使用Python来处理。


不能在类体中引用类本身,因为在执行类体时类不存在。(如果前一句话令人困惑,那么阅读有关元类的内容将清除这一点,或者使您更加困惑。)

在实例方法中,可以使用self.__class__引用实例的类,但这里要小心。这将是实例的实际类,通过继承的力量,该类可能不是在其中定义方法的类。

在类方法中,类作为第一个参数传入,很像实例是实例方法的第一个参数:

1
2
3
4
5
6
class MyClass(object):
    @classmethod
    def foo(cls):
        print cls.__name__

MyClass.foo() # Should print"MyClass"

与实例方法一样,实际类可能因继承而有所不同。

1
2
3
4
class OtherClass(MyClass):
    pass

OtherClass.foo() # Should print"OtherClass"

如果你真的需要在MyClass的方法中引用MyClass,那么除非你使用魔法,否则你将不得不把它称为MyClass。这种魔法比它的价值更麻烦。


因为名称self被明确定义为myFunction参数的一部分。方法的第一个参数是调用该方法的实例;在类体中,没有"我们正在处理的实例",因为类体处理类的每个可能的实例(包括那些还不一定存在的实例),所以没有一个可以称为self的特定对象。

如果您想引用类本身,而不是它的某个实例,则将其拼写为self.__class__(或者,对于py2中的新样式类和py3中的所有类,type(self),在self存在的任何地方。如果您希望能够在不存在self的情况下处理这个问题,那么您可能希望查看与任何特定实例没有关联的类方法,因此将类本身替换为self。如果你真的需要在课堂上做这个(而且,你可能不需要),你只需要用名字来称呼它。


self不是关键字,它只是一种约定。这些方法是类对象(不是实例)的属性,但它们将实例作为第一个参数接收。如果你愿意的话,你可以把这个参数改名为xyzzy,它的工作方式仍然是一样的。

但是(应该很明显)您不能在方法主体之外引用方法参数。在class块内部,但在任何方法之外,self都是未定义的。这个概念甚至没有意义——在评估class块时,类的任何实例都不可能存在。