在Python中检查变量是否属于一个类

14

我有一个小的类, 其内容如下:

class Gender(object):
    MALE = 'M'
    FEMALE = 'F'

我有一个参数变量,它只能是 MF。为确保它只是这样,我这样做:

>>> parameter = 'M'
>>> if parameter not in (Gender.MALE, Gender.FEMALE)
...     print "Invalid parameter"
...
Invalid parameter
>>>

现在我有一个包含美国所有州的类,如下所示:

class States(object):
    ALABAMA = 'AL'
    ALASKA = 'AK'
    ARIZONA = 'AZ'
    ARKANSAS = 'AR'
    CALIFORNIA = 'CA'
    COLORADO = 'CO'
    CONNECTICUT = 'CT'
    DELAWARE = 'DE'
    DISTRICTOFCOLUMBIA = 'DC'
    ....
....

就像上面的例子一样,我的参数现在是AL。然而,美国有50个州,我不能实际上像上面那样使用一个有50个变量的元组。是否有更好的方法?我确实读过isinstance,但它没有给我期望的结果。


2
如果您正在使用Python 3,请查看enum - Andrea Corbellini
你应该使用 枚举类型 - shx2
如果我没记错的话,应该在某个地方有一个 Python 2 枚举类型的示例。 - Andrea Corbellini
@AndreaCorbellini 我相信有很多枚举的用法。 - Peter Wood
显示剩余2条评论
4个回答

15

您可以使用__dict__属性来访问一个类的属性,例如:

In [1]: class Foo(object):
   ...:     bar = "b"
   ...:     zulu = "z"
   ...:     
In [2]: "bar"  in Foo.__dict__
Out[2]: True

如果你要查找值,请使用__dict__.values()

In [3]: "b" in Foo.__dict__.values()
Out[3]: True

正如Peter Wood指出的那样,vars()内置函数也可用于检索__dict__

In [12]: "b" in vars(Foo).values()
Out[12]: True

__dict__属性用作类的命名空间,因此会返回类中的所有方法、魔术方法和私有属性,因此为了保证鲁棒性,您可能需要稍微修改搜索内容。

在您的情况下,您可能需要使用一个classmethod,例如:

class States(object):
    ALABAMA = "AL"
    FLORIDA = "FL"

    @classmethod
    def is_state(cls, to_find):
        print(vars(cls))
        states = [val for key, val in vars(cls).items()
                  if not key.startswith("__")
                  and isinstance(val, str)]
        return to_find in states

States.is_state("AL") # True
States.is_state("FL") # True
States.is_state("is_state") # False
States.is_state("__module__") # False

更新本文明确回答了原帖问题,但读者们也可能对Python 3中的Enum库感兴趣,该库很可能是这类数据更好的容器。



1
请注意,如果存在与键匹配的方法,则此操作将返回错误的结果。 - Burhan Khalid
我的类中没有方法,所以这应该足够了...谢谢。 - Amistad
请注意,这种方法无法与__slots__一起使用,更好的方法是使用hasattr,但它与在类字典中查找不同,因为它将在整个继承树中查找。 - Ashwini Chaudhary
1
你可以使用 vars(Foo) 访问 __dict__ - Peter Wood
2
@AshwiniChaudhary 如果 OP 想要查找 bar,那么 hasattr() 就非常好用了,但他正在尝试查找 "b" - Ian Clark

6
为什么不使用字典呢?它更简单,查找也更容易。
states = {'AL': 'Alabama', 'AK': 'Alaska' ... }
test_state = 'Foo'

if test_state not in states.keys():
    print('{} is not valid input'.format(test_state))

1
你甚至不需要使用 .keys(),因为 in 已经检查了键。if test_state not in states: - Daniel Roseman
1
你说得对 - 我只是习惯使用 .keys() - Burhan Khalid
1
如果您使用dict构造函数,可以使用关键字参数而不是创建字符串。例如:dict(AL='Alabama', AK='Alaska') - Peter Wood
@Burhan,states类已经为其他目的定义了,如果我在不同的格式中重新创建相同的内容,这将是重复的。因此,我特别寻找访问类中静态变量的信息。 - Amistad

5
我建议使用枚举(Enum)来定义“性别”和“州”两个变量。
枚举 是 Python 3 标准库的一部分。如果你使用的是 Python 2,请使用 enum34,并通过pip install enum34安装。
from enum import Enum
class States(Enum):
    ALABAMA = 'AL'
    ALASKA = 'AK'
    ARIZONA = 'AZ'
    ARKANSAS = 'AR'
    CALIFORNIA = 'CA'
    COLORADO = 'CO'
    CONNECTICUT = 'CT'
    DELAWARE = 'DE'
    DISTRICTOFCOLUMBIA = 'DC'
    ...

然后,您可以通过检查变量是否处于其中一种状态来进行检查。
isinstance(variable, States)

0

实际上,如果您能在开头设置好所有参数,最好只放置必需的参数而不是默认参数。这将强制用户设置参数。然而,出于各种原因,通常您可能想稍后设置属性。

我发现定义一个类“Required”非常方便,我可以将其用作占位符,并在对象“发送到生产”之前使用函数validate进行验证。

class Required(object):
    def __init__(self,description=None):
        self.description = description
    def __repr__(self): 
        return 'Required attribute:%s' %self.description



class MyClass(object):
    def __init__(self):
        self.ID = Required(self.ID = Required("ID is mandatory, please set it using set_ID method."))
        self.context = None
        self.type = "MyClass"


    def set_ID(self,MyClass_ID):
        """
        The id property identifies this MyClass with the URL at which it is available online.
        """
        # check MyClass_ID is valid before assigning it
        # valid(ID)
        self.ID = MyClass_ID

    def validate(self):
        for i in self.__dict__.values():
            if isinstance(i, Required):
                print(i)
                # Warining or raise error

g = MyClass()
g.validate()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接