2

I have the following class with two static attributes (common to every instances)

class Seller:
    fields = {
        "url": True,
        "availability": False,
        "visibility": False,
        "country": False,
        "origin_website": False
    }
    required_fields = [f for f in Seller.fields.keys() if Seller.fields[f]]

    def __init__(self):
        ...

When attempting to create an instance of seller, I get the following error.

required_fields = [f for f in Seller.fields.keys() if fields[f]]
NameError: name 'Seller' is not defined

I've tried to remove the Seller reference, but it yields an another error

required_fields = [f for f in fields.keys() if fields[f]]
NameError: name 'fields' is not defined

I know I might miss something obvious as far as static variables are concerned, but can't figure what exactly.

pp492
  • 511
  • 1
  • 3
  • 12
  • did you try like this, [f for f in Seller.fields.keys() if Seller.fields[f]] ? – PurushothamC Dec 14 '18 at 10:14
  • @VillageMonkey: Isn't that exactly what is written in the question? – Graipher Dec 14 '18 at 10:21
  • The second version was working with Python 2, things got more complicated with Python 3. Similar questions have been asked on SO already, see https://stackoverflow.com/questions/13905741/accessing-class-variables-from-a-list-comprehension-in-the-class-definition – Thierry Lathuille Dec 14 '18 at 10:32
  • It's actually not particularly obvious. It is a wart in the language. Essentially, list comprehensions create a function scope,just like a method you would define in the class scope. And similar to that method / function, it won't have access to the variables in the class body. – juanpa.arrivillaga Dec 14 '18 at 11:11

1 Answers1

2

You cannot access the class Seller from static attributes because these are instantiated while the class is instantiated and not yet bound to the name Seller. There are a couple of ways to work around that:

1. Use inheritance

class SellerBase:
    fields = {
        "url": True,
        "availability": False,
        "visibility": False,
        "country": False,
        "origin_website": False
    }


class Seller(SellerBase):
    required_fields = [f for f in SellerBase.fields.keys() if SellerBase.fields[f]]

    def __init__(self):
        ...

2. Assigning the attribute later

class Seller:
    fields = {
        "url": True,
        "availability": False,
        "visibility": False,
        "country": False,
        "origin_website": False
    }

    def __init__(self):
        ...

Seller.required_fields = [f for f in Seller.fields.keys() if Seller.fields[f]]

3. moving fields out of Seller

fields = {
    "url": True,
    "availability": False,
    "visibility": False,
    "country": False,
    "origin_website": False
}


class Seller:
    required_fields = [f for f in fields.keys() if fields[f]]

    def __init__(self):
        ...

I'd most likely use option 3, but it really depends on your use case.

Does this answer your question?

Felix
  • 6,131
  • 4
  • 24
  • 44