简体   繁体   English

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

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

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. 编辑:这一点是我试图从类内部引用类名称与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. class ._ name _这样类名在代码的任何地方都没有硬编码,因此重用代码更容易。

EDIT 2: From what I've learned from the answers below, what I'm trying to do is impossible. 编辑2:从我从下面的答案中学到的,我想要做的是不可能的。 I'll have to find a different way. 我必须找到一种不同的方式。 Mission abandoned. 任务放弃了。

EDIT 3: Here is specifically what I'm trying to do: 编辑3:这是我正在尝试做的事情:

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

Note that self is not defined at the time when you want the class to refer to itself for the assignment to work. 请注意,当您希望类引用自身以使赋值工作时,不会定义self This is because (in addition to being named arbitrarily), self refers to instances and not classes. 这是因为(除了被任意命名), self指的是实例而不是类。 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) . 在方法中,您始终可以使用type(self) That will get the subclass of MyClass that created the current instance. 这将获得创建当前实例的MyClass的子类。 If you want to hard-code to MyClass , that name will be available in the global scope of the methods. 如果要对MyClass进行硬编码,则该名称将在方法的全局范围内可用。 This will allow you to do everything that your example would allow if it actually worked. 这将允许您执行示例在实际工作时允许的所有内容。 Eg, you can just do MyClass.some_attribute inside your methods. 例如,您可以方法中执行MyClass.some_attribute

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. 它使用元类AutoViewConfigMeta和一个新的装饰器来标记您希望view_config应用于的方法。 I spoofed the view_config decorator. 我欺骗了view_config装饰器。 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. 元类__new__只循环遍历类字典并查找由auto_view_config装饰器标记的方法。 It cleans off the mark and applies the view_config decorator with the appropriate class name. 它清除没谱,并应用view_config 适当的类名装饰。

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. 如果您有任何疑问,请告诉我。

Python has an "explict is better than implicit" design philosophy. Python有一个“明显比隐含更好”的设计理念。

Many languages have an implicit pointer or variable in the scope of a method that (eg this in C++) that refers to the object through which the method was invoked. 许多语言中具有方法,该方法的范围的隐式指针或变量(例如this其是指通过调用该方法的对象在C ++)。 Python does not have this. Python没有这个。 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++). 你可以称它为任何你想要的( self不是像关键字this在C ++中)。 The name self is convention rather than a syntactic rule. 名称self是约定而不是语法规则。

Your method myFunction defines the variable self as a parameter so it works. 你的方法myFunction将变量self定义为参数,因此它可以工作。 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. 我不知道你做你想做的直接方式,我从来没有在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. 也许假设您正在制作哪些可以使用Python以另一种方式处理。

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只是一个名字,在这种情况下你的self是一个类变量而不是用于调用它的对象,

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. self被视为一个普通变量,并且没有定义,因为函数中的self来自用于调用的对象。

you want to treat the object reference in self as a class variable which is not possible. 您希望将self的对象引用视为不可能的类变量。

self isn't a keyword, it's just a convention. self不是关键字,它只是一种约定。 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. 如果你愿意,可以将参数重命名为xyzzy ,它仍然可以以相同的方式工作。

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. class块内,但在任何方法之外, self是未定义的。 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. 这个概念甚至没有意义 - 在评估class块时,还没有可能存在类的实例。

Because the name self is explicitly defined as part of the arguments to myFunction . 因为名称self被明确定义为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 . 在类体中,没有“我们正在处理的实例”,因为类主体处理类的每个可能的实例(包括那些不一定存在的实例) - 所以,没有可称为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. 如果你想引用类本身 ,而不是它的一些实例,那么拼写为self.__class__ class__(或者,对于Py2中的新式类和Py3中的所有类, type(self)self存在。 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 . 如果您希望能够在存在self情况下处理此问题,那么您可能希望查看与任何特定实例无关的类方法 ,因此请使用类本身代替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. 如果你真的需要在类体中这样做(并且你可能没有),你只需要按名称调用它。

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. 在实例方法中,您可以使用self.__class__引用实例的类,但请注意这里。 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. 如果你真的需要参考MyClass的方法中MyClass ,你几乎将不得不把它称为MyClass ,除非你使用魔法。 This sort of magic is more trouble than it is worth. 这种魔法比它的价值更麻烦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM