简体   繁体   中英

How can I define a class attribute from a variable in Python?

I need to access a variable from a nested class. The objective is to create a Schema using the Marshmallow library. The code looks like this :

class ParserScheme(Schema):

    class Meta:
        # Here I meed to access the value of my_variable :
        result = func(my_variable)

my_variable = 'foo'
my_parser = ParserScheme()

If I manage to pass my variable as a class attribute of the outer class (ParserScheme), then it is easy to get it into the inner class (Meta).

class ParserScheme(Schema):
    class_attribute = my_variable
    class Meta:
        result = func(ParserScheme.class_attribute)

my_variable = 'foo'
my_parser = ParserScheme()

However I can't seem to find a way to dynamically set a class attribute. And if I set a "classic" attribute (I mean an attribute of instances of the class, not of the class itself), then I can't access it from the inner class.

I also thought of using a global variable, but that does not really quite satisfy me. Is there another way of doing this ?

I am rather new to OOP, and I am not sure I understand really well the concept of class attribute. I fear that there is an easy way to do that but I did not see it as I am to focused on the way I think this should work...

Your first example breaks because name my_variable is not yet defined when the class Meta statement's body is executed.

You second example won't work either for the same reason ( my_variable is not yet defined when the class ParserScheme statement's body is executed), and if it was it would still break when executing the class Meta statement's body because it will be executed as part of the class ParserScheme statement's body hence before the name ParserScheme is defined.

What you have to understand here is that class and def are executable statements which (if at the top level of a module) are executed sequentially when the module is first imported into the current process. In the case of a class statement, the statement's body is first sequentially executed in a dedicated namespace then this namespace is passed to the metaclass constructor and used to create the class object's attributes ( YourClass.__dict__ ).

To make a long story short: in a class statement body, you just cannot reference names that are not yet defined in the current or enclosing scope. Period.

The obvious solution here would be to define my_variable before the class statement, but I assume you want it to be more dynamic ? If yes, you'll have to define your class in a function:

def create_parser_class(my_variable):

    class ParserScheme(Schema):

        class Meta:
            result = func(my_variable)


    return ParserScheme


my_variable = 42
cls = create_parser_class(my_variable)
my_parser = cls()

But I can't garantee it will work out of the box (nor even work at all FWIW) with Marshmallow (which I never used but probably has some metaclass stuff happening). Also depending on what my_variable is used for, you may want to make sure you don't have two calls to create_parser_class with the same value as argument.

As a last note : you perhaps have a XY problem here - that's sometimes the case when someone asks how to do something a bit non-obvious or unusual. Perhaps you should edit your post to explain the "problem behind" - that is, the problem you are actually trying to solve with this "solution".

Oh and yes:

I am rather new to OOP, and I am not sure I understand really well the concept of class attribute

In Python, classes are objects too (instances of their metaclass, by default the type object), and as such they have their own attributes. Every name you define (with an assignment, a def statement, a class statement or an import statement) at the top-level of the class statement becomes an attribute of the class object (unless a custom metaclass makes some transformations on the way, that is).

Class attributes are accessible from the instances too (unless shadowed by an eponym instance variable), and are shared between all instances.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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