提问人:rwbyrd 提问时间:7/26/2022 更新时间:7/26/2022 访问量:48
如何在 Python 中重新初始化类中的变量
How to Reinitialize Variables in a Class in Python
问:
我使用 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 重新初始化变量。我该怎么做?
答:
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 :Common
property
# 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
很棒的答案!这既易于理解又易于理解。谢谢!
评论