如何在 Python 中重新初始化类中的变量

How to Reinitialize Variables in a Class in Python

提问人:rwbyrd 提问时间:7/26/2022 更新时间:7/26/2022 访问量:48

问:

我使用 Selenium 和 Python 创建了一个测试,以使用类中的定位器。

测试:

def testPage(driver, url):
    login(driver, url)
    activateProfile(driver, url)

    driver.get(my_url)
    assert_true(driver, *Common.user_lbl)
    assert_true(driver, *Common.pass_lbl)
    .
    .

类:

class Common():
    locator = namedtuple('Locator', ['elem_type', 'elem_target', 'elem_val'])

    user_lbl = locator("By.ID", "username", "username")
    pass_lbl = locator("By.ID", "password", "password")
    .
    .

我想更改类,以便值“user_lbl”和“pass_lbl”可以由全局变量“version”的值确定。但是,该变量是在类 Common 初始化后确定的。我希望类文件看起来更像这样:

class Common():
    locator = namedtuple('Locator', ['elem_type', 'elem_target', 'elem_val'])

    if global.version == 5:
        user_lbl = locator("By.ID", "username", "username")
        pass_lbl = locator("By.ID", "password", "password")
    else:
        user_lbl = locator("By.CLASS_NAME", "user", "username")
        pass_lbl = locator("By.CLASS_NAME", "pass", "password")

    .
    .

...我希望这些变量是根据我的“版本”变量确定的。为了实现这一点,我需要一种方法来强制 Class Common 重新初始化变量。我该怎么做?

python-3.x python-2.7 selenium-web驱动程序

评论


答:

1赞 Lenormju 7/26/2022 #1

对于这样的情况,有属性装饰器

# n°1
from collections import namedtuple  # stdlib

class Common:
    locator = namedtuple('Locator', ['elem_type', 'elem_target', 'elem_val'])

    @property
    def user_lbl(self):
        if VERSION == 5:
            return self.locator("By.ID", "username", "username")
        else:
            return self.locator("By.CLASS_NAME", "user", "username")

    @property
    def pass_lbl(self):
        if VERSION == 5:
            return self.locator("By.ID", "password", "password")
        else:
            return self.locator("By.CLASS_NAME", "pass", "password")

VERSION = 4  # default value
print(Common().user_lbl)  # Locator(elem_type='By.CLASS_NAME', elem_target='user', elem_val='username')
print(Common().pass_lbl)  # Locator(elem_type='By.CLASS_NAME', elem_target='pass', elem_val='password')
VERSION = 5
print(Common().user_lbl)  # Locator(elem_type='By.ID', elem_target='username', elem_val='username')
print(Common().pass_lbl)  # Locator(elem_type='By.ID', elem_target='password', elem_val='password')
#           ^^

它使调用看起来像常规字段的方法成为可能。但它需要一个对象,即类实例才能工作。如果你不想有对象(而只是一个像命名空间一样的类定义),你可以使用 staticmethod 装饰器

# n°2
from collections import namedtuple  # stdlib

class Common:
    locator = namedtuple('Locator', ['elem_type', 'elem_target', 'elem_val'])

    @staticmethod
    def user_lbl():
        if VERSION == 5:
            return Common.locator("By.ID", "username", "username")
        else:
            return Common.locator("By.CLASS_NAME", "user", "username")

    @staticmethod
    def pass_lbl():
        if VERSION == 5:
            return Common.locator("By.ID", "password", "password")
        else:
            return Common.locator("By.CLASS_NAME", "pass", "password")

VERSION = 4  # default value
print(Common.user_lbl())  # Locator(elem_type='By.CLASS_NAME', elem_target='user', elem_val='username')
print(Common.pass_lbl())  # Locator(elem_type='By.CLASS_NAME', elem_target='pass', elem_val='password')
VERSION = 5
print(Common.user_lbl())  # Locator(elem_type='By.ID', elem_target='username', elem_val='username')
print(Common.pass_lbl())  # Locator(elem_type='By.ID', elem_target='password', elem_val='password')
#                    ^^

如果你真的,真的,真的,只想写,那么你可能需要@staticmethod@property但这会使事情更难维护。Common.user_lbl

另一种方法是实例化一个实例,该实例以不同的命名方式命名,该类声明其 s :Commonproperty

# n°3
from collections import namedtuple  # stdlib

class _Common:  # or whatever
    locator = namedtuple('Locator', ['elem_type', 'elem_target', 'elem_val'])

    @property
    def user_lbl(self):
        if VERSION == 5:
            return self.locator("By.ID", "username", "username")
        else:
            return self.locator("By.CLASS_NAME", "user", "username")

    @property
    def pass_lbl(self):
        if VERSION == 5:
            return self.locator("By.ID", "password", "password")
        else:
            return self.locator("By.CLASS_NAME", "pass", "password")

Common = _Common()

VERSION = 4  # default value
print(Common.user_lbl)  # Locator(elem_type='By.CLASS_NAME', elem_target='user', elem_val='username')
print(Common.pass_lbl)  # Locator(elem_type='By.CLASS_NAME', elem_target='pass', elem_val='password')
VERSION = 5
print(Common.user_lbl)  # Locator(elem_type='By.ID', elem_target='username', elem_val='username')
print(Common.pass_lbl)  # Locator(elem_type='By.ID', elem_target='password', elem_val='password')

这也有效,但我建议不要这样做,因为它偏离了 PEP8 命名约定(实例名称应为小写)。

最后,也许您稍后会添加其他配置,在这种情况下,它可能很方便:

# n°4
from collections import namedtuple  # stdlib

class Common:
    def __init__(self, version: int):
        self._version = version

    locator = namedtuple('Locator', ['elem_type', 'elem_target', 'elem_val'])

    @property
    def user_lbl(self):
        if self._version == 5:
            return self.locator("By.ID", "username", "username")
        else:
            return self.locator("By.CLASS_NAME", "user", "username")

    @property
    def pass_lbl(self):
        if self._version == 5:
            return self.locator("By.ID", "password", "password")
        else:
            return self.locator("By.CLASS_NAME", "pass", "password")

common = Common(4)
print(common.user_lbl)  # Locator(elem_type='By.CLASS_NAME', elem_target='user', elem_val='username')
print(common.pass_lbl)  # Locator(elem_type='By.CLASS_NAME', elem_target='pass', elem_val='password')
common = Common(5)
print(common.user_lbl)  # Locator(elem_type='By.ID', elem_target='username', elem_val='username')
print(common.pass_lbl)  # Locator(elem_type='By.ID', elem_target='password', elem_val='password')

在这种情况下,您不需要全局变量。

我的首选解决方案是 n°4(带参数的类实例),然后是 n°2(静态方法)。但要做出自己的选择:)

评论

1赞 rwbyrd 7/27/2022
很棒的答案!这既易于理解又易于理解。谢谢!