5

I have a Python class that contains all the AWS regions. I wrote a class method that would return me the list of all the regions. Is there a better way of returning all the class variable values so I don't have to hard-code all the values in the return statement like I am doing in the example below?

class AwsRegion():
    '''
    Class to define AWS Regions
    '''
    OHIO = 'us-east-2'
    NORTH_VIRGINIA = 'us-east-1'
    NORTH_CALIFORNIA = 'us-west-1'
    OREGON = 'us-west-2'
    MUMBAI = 'ap-south-1'
    SEOUL = 'ap-northeast-2'
    SINGAPORE = 'ap-southeast-1'
    SYDNEY = 'ap-southeast-2'
    TOKYO = 'ap-northeast-1'
    FRANKFURT = 'eu-central-1'
    IRELAND = 'eu-west-1'
    LONDON = 'eu-west-2'
    SAO_PAULO = 'sa-east-1'

    @classmethod
    def all(cls, ):
        return [AwsRegion.OHIO, AwsRegion.NORTH_VIRGINIA, AwsRegion.NORTH_CALIFORNIA, AwsRegion.OREGON, \
            AwsRegion.MUMBAI, AwsRegion.SEOUL, AwsRegion.SINGAPORE, AwsRegion.SYDNEY, AwsRegion.TOKYO, \
            AwsRegion.FRANKFURT, AwsRegion.IRELAND, AwsRegion.LONDON, AwsRegion.SAO_PAULO]
2
  • all is a class attribute too. Do you mean anything that isn't a callable or otherwise a descriptor? Commented Jun 27, 2017 at 21:16
  • 1
    There must be a simpler way to return those values than hardcoding them in a list... Commented Jun 27, 2017 at 21:20

4 Answers 4

6

As a general reference, you can get the attributes of any class through the following ways.
Choose depending on your needs:

__dict__:

Will return a dict of all writeable class attributes. This is usually what you need.

my_obj = MyClass()
attributes = my_obj.__dict__

vars():

Same result as __dict__, but using this instead is considered best practice.

my_obj = MyClass()
attributes = vars(my_obj)

dir():

Will return all class attributes, including those that aren't made by you but are inherited from object.

my_obj = MyClass()
attributes = dir(my_obj)

In your case, using vars() will work just fine, as demonstrated by Martijn Pieters in his answer.

Sign up to request clarification or add additional context in comments.

1 Comment

You mentioned vars() but typed dir(myObj) in this line: vars = dir(myObj). Is that a typo?
5

In this case, you can enumerate all the attributes of the class that are uppercase; I'd use the vars() function to access the class namespace:

@classmethod
def all(cls):
    return [value for name, value in vars(cls).items() if name.isupper()]

Demo:

>>> class AwsRegion():
...     '''
...     Class to define AWS Regions
...     '''
...     OHIO = 'us-east-2'
...     NORTH_VIRGINIA = 'us-east-1'
...     NORTH_CALIFORNIA = 'us-west-1'
...     OREGON = 'us-west-2'
...     MUMBAI = 'ap-south-1'
...     SEOUL = 'ap-northeast-2'
...     SINGAPORE = 'ap-southeast-1'
...     SYDNEY = 'ap-southeast-2'
...     TOKYO = 'ap-northeast-1'
...     FRANKFURT = 'eu-central-1'
...     IRELAND = 'eu-west-1'
...     LONDON = 'eu-west-2'
...     SAO_PAULO = 'sa-east-1'
...     @classmethod
...     def all(cls):
...         return [value for name, value in vars(cls).items() if name.isupper()]
...
>>> AwsRegion.all()
['us-east-2', 'us-east-1', 'us-west-1', 'us-west-2', 'ap-south-1', 'ap-northeast-2', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'eu-central-1', 'eu-west-1', 'eu-west-2', 'sa-east-1']

3 Comments

Is this recommended, considering class method is not returning an instance of class?
@Sajal: classmethods can return anything, they are not required to return a class. That's not what a classmethod is about. Classmethods are simply bound to the class they are accessed on, or the class of an instance they are accessed on. One of their use cases is to return class-specific information, like all the uppercase attributes here.
Oh cool! While checking for class methods on GFG, there it was mentioned that return type is class instance (modified), that's why needed to confirm, if this is a safe practice. Thanks!
2

It looks like what you might be doing is accidentally creating an Enum type.

If your AwsRegion class is only used to store these values (not lots of other complex behavior), try making it a subclass of Enum. This would give you a handful of nice methods without having to recreate it all yourself and would make your code clearer to others who know what enumerate types are.

from enum import Enum

class AwsRegion2(Enum):
    OHIO = 'us-east-2'
    NORTH_VIRGINIA = 'us-east-1'
    NORTH_CALIFORNIA = 'us-west-1'
    OREGON = 'us-west-2'
    MUMBAI = 'ap-south-1'
    SEOUL = 'ap-northeast-2'
    SINGAPORE = 'ap-southeast-1'
    SYDNEY = 'ap-southeast-2'
    TOKYO = 'ap-northeast-1'
    FRANKFURT = 'eu-central-1'
    IRELAND = 'eu-west-1'
    LONDON = 'eu-west-2'
    SAO_PAULO = 'sa-east-1'


print(list(AwsRegion2))

Comments

1

From the combination of the mentioned answers, I think this is more efficient:

from enum import Enum

class AwsRegion2(Enum):
    OHIO = 'us-east-2'
    NORTH_VIRGINIA = 'us-east-1'
    NORTH_CALIFORNIA = 'us-west-1'
    OREGON = 'us-west-2'
    MUMBAI = 'ap-south-1'
    SEOUL = 'ap-northeast-2'
    SINGAPORE = 'ap-southeast-1'
    SYDNEY = 'ap-southeast-2'
    TOKYO = 'ap-northeast-1'
    FRANKFURT = 'eu-central-1'
    IRELAND = 'eu-west-1'
    LONDON = 'eu-west-2'
    SAO_PAULO = 'sa-east-1'

    @classmethod
    def all(cls):
        return [variable.value for variable in list(cls)]

print(AwsRegion2.all())

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.