Python - 定义仅使用一次的常量变量的最便捷方式
Python - most convenient way to define constant variables used just once
假设我有一个文件 "icon.ico" 和一个 url "url.com".
它们将在 class 中仅使用一次 - "icon.ico" 将设置为某些 window,我们将在一个方法中对 url 执行请求。
我有三种方法来定义这些变量。
第一种方式 - 定义为全局常量
#in the top of the file
ICON = "icon.ico"
URL = "http://url.com"
#and then
def setIcon(self):
self.setWindowIcon(QtGui.QIcon(ICON))
def getData(self):
content = requests.get(URL).content
第二种方式 - 定义为 class
的变量
def __init__(self):
self.url = "http://url.com"
self.icon = "icon.ico"
第三种方式 - 仅在将要使用的方法中定义
def setIcon(self):
icon = "icon.ico"
def getData(self):
url = "http://url.com"
您忘记了将它们定义为 class-level 常量的选项:
class Foo(...)
ICON = "xxx"
URL = "YYY"
将它们定义为 class 变量可能是最 future-proof 的方法,因为您以后可以使用 dependency injection to change these variables, which is very useful for unit testing。例如:
class Server:
def __init__(self, url, icon):
self.url = url
self.icon = icon
server = Server('url.com', 'file.ico')
# in your tests, you may want to use a different ico/url
test_server = Server('url.com', 'test_icon.ico')
关于 getter 和 setter 的注释:
另请注意,在 Python 中往往会避免使用 getter 和 setter,如果需要验证,则使用 properties 代替 ,或者 class 有很多的依赖代码被重构。在 Java 和 C 等预编译语言中,getters/setters 用于封装,以便以后可以更改实现,但在 Python 中,为了性能和清晰度而避免使用。因此,首先,可以正常访问变量,如果实现发生变化,您可以使用 @property
和 @variable.setter
装饰器,以便使用 getter 和 setter,即使您看起来正在访问直接变量。
原来你可以直接访问icon
。
print(server.icon)
但是假设稍后你将 class 中的 icon
重构为 _icon_file
和 _icon_image
并在每次设置时加载文件,但其余的您的应用需要 icon
变量。这就是 getter 和 setter 通常的用途(与设置变量上的任何 checks/conversion 一起),因此我们现在可以为 icon
添加 getter 和 setter,即使 icon
变量不再存在:
class Server:
def __init__(self, url, icon_filename):
self.url = url
self._icon_filename = icon_filename
self._icon_image = self._load_icon(icon_filename)
@property
def icon(self):
"""
Get the icon file name
@returns str of the icon filename
"""
return self._icon_filename
@icon.setter
def icon(self, icon_filename):
"""
Load a new icon file as the icon
@param icon_filename the relative path to the icon file
"""
if icon_filename[-4:] != '.ico':
raise Exception('Must be of .ico format')
self._icon_filename = icon_filename
self._icon_image = self._load_icon(icon_filename)
def _load_icon(self, icon_filename):
"""
Load a .ico file, and maybe do some other stuff
@returns Image of the loaded icon
@private
"""
# implementation here...
server = Server('url.com', 'file.ico')
print(server.icon) # file.ico
server.icon = 'icon2.ico' # sets and loads new icon
print(server.icon) # icon2.ico
server.icon = 'icon3.jpg' # throws an exception
经验法则
- 一般来说,您应该避免使用全局变量,因为它们在您导入模块后一直存在于内存中,直到程序完成(第一种情况)
- 一般来说,您应该避免在函数内部固定值(第 2 种和第 3 种情况),因为这会使函数文件可重用。
而不是:
def __init__(self):
self.url = "http://url.com"
self.icon = "icon.ico"
或
def setIcon(self):
icon = "icon.ico"
优先:
def __init__(self, url, icon):
self.url = url
self.icon = icon
或者,如果您认为值将有 90% 相同:
def __init__(self, url="http://url.com", icon="icon.ico"):
self.url = url
self.icon = icon
何时使用每个案例的提示
第一种方式 - 定义为全局常量
- 常量作为模块作用域常量有意义。请记住,多个 classes 和函数可以在同一个模块中声明。这意味着常量将在整个模块中使用,并且不属于任何特定的 class.
- 您需要快速找到常量,通常是为了改变它的值。在这种情况下,也许您真的不需要常量,而是变量。
第二种方式 - 定义为 class
的变量
- 如果是class的变量,则不是常量。如果要使用 class 的常量或变量 (在 class 级别而不是实例级别),您应该使用 第 4 种方式 - 作为 class 级别常量.
- 如果你想要一个实例级别的常量或变量,你应该使用 2dn 经验法则
第三种方式 - 仅在将要使用的方法中定义
- 你应该避免这种方式以支持第二条经验法则
第 4 种方式 - 作为 class 级别常数
- 推荐的方法仅适用于共享同一class的所有实例的变量和常量,这意味着,实际上,class级别或class范围
假设我有一个文件 "icon.ico" 和一个 url "url.com".
它们将在 class 中仅使用一次 - "icon.ico" 将设置为某些 window,我们将在一个方法中对 url 执行请求。
我有三种方法来定义这些变量。
第一种方式 - 定义为全局常量
#in the top of the file
ICON = "icon.ico"
URL = "http://url.com"
#and then
def setIcon(self):
self.setWindowIcon(QtGui.QIcon(ICON))
def getData(self):
content = requests.get(URL).content
第二种方式 - 定义为 class
的变量def __init__(self):
self.url = "http://url.com"
self.icon = "icon.ico"
第三种方式 - 仅在将要使用的方法中定义
def setIcon(self):
icon = "icon.ico"
def getData(self):
url = "http://url.com"
您忘记了将它们定义为 class-level 常量的选项:
class Foo(...)
ICON = "xxx"
URL = "YYY"
将它们定义为 class 变量可能是最 future-proof 的方法,因为您以后可以使用 dependency injection to change these variables, which is very useful for unit testing。例如:
class Server:
def __init__(self, url, icon):
self.url = url
self.icon = icon
server = Server('url.com', 'file.ico')
# in your tests, you may want to use a different ico/url
test_server = Server('url.com', 'test_icon.ico')
关于 getter 和 setter 的注释:
另请注意,在 Python 中往往会避免使用 getter 和 setter,如果需要验证,则使用 properties 代替 ,或者 class 有很多的依赖代码被重构。在 Java 和 C 等预编译语言中,getters/setters 用于封装,以便以后可以更改实现,但在 Python 中,为了性能和清晰度而避免使用。因此,首先,可以正常访问变量,如果实现发生变化,您可以使用 @property
和 @variable.setter
装饰器,以便使用 getter 和 setter,即使您看起来正在访问直接变量。
原来你可以直接访问icon
。
print(server.icon)
但是假设稍后你将 class 中的 icon
重构为 _icon_file
和 _icon_image
并在每次设置时加载文件,但其余的您的应用需要 icon
变量。这就是 getter 和 setter 通常的用途(与设置变量上的任何 checks/conversion 一起),因此我们现在可以为 icon
添加 getter 和 setter,即使 icon
变量不再存在:
class Server:
def __init__(self, url, icon_filename):
self.url = url
self._icon_filename = icon_filename
self._icon_image = self._load_icon(icon_filename)
@property
def icon(self):
"""
Get the icon file name
@returns str of the icon filename
"""
return self._icon_filename
@icon.setter
def icon(self, icon_filename):
"""
Load a new icon file as the icon
@param icon_filename the relative path to the icon file
"""
if icon_filename[-4:] != '.ico':
raise Exception('Must be of .ico format')
self._icon_filename = icon_filename
self._icon_image = self._load_icon(icon_filename)
def _load_icon(self, icon_filename):
"""
Load a .ico file, and maybe do some other stuff
@returns Image of the loaded icon
@private
"""
# implementation here...
server = Server('url.com', 'file.ico')
print(server.icon) # file.ico
server.icon = 'icon2.ico' # sets and loads new icon
print(server.icon) # icon2.ico
server.icon = 'icon3.jpg' # throws an exception
经验法则
- 一般来说,您应该避免使用全局变量,因为它们在您导入模块后一直存在于内存中,直到程序完成(第一种情况)
- 一般来说,您应该避免在函数内部固定值(第 2 种和第 3 种情况),因为这会使函数文件可重用。
而不是:
def __init__(self):
self.url = "http://url.com"
self.icon = "icon.ico"
或
def setIcon(self):
icon = "icon.ico"
优先:
def __init__(self, url, icon):
self.url = url
self.icon = icon
或者,如果您认为值将有 90% 相同:
def __init__(self, url="http://url.com", icon="icon.ico"):
self.url = url
self.icon = icon
何时使用每个案例的提示
第一种方式 - 定义为全局常量
- 常量作为模块作用域常量有意义。请记住,多个 classes 和函数可以在同一个模块中声明。这意味着常量将在整个模块中使用,并且不属于任何特定的 class.
- 您需要快速找到常量,通常是为了改变它的值。在这种情况下,也许您真的不需要常量,而是变量。
第二种方式 - 定义为 class
的变量- 如果是class的变量,则不是常量。如果要使用 class 的常量或变量 (在 class 级别而不是实例级别),您应该使用 第 4 种方式 - 作为 class 级别常量.
- 如果你想要一个实例级别的常量或变量,你应该使用 2dn 经验法则
第三种方式 - 仅在将要使用的方法中定义
- 你应该避免这种方式以支持第二条经验法则
第 4 种方式 - 作为 class 级别常数
- 推荐的方法仅适用于共享同一class的所有实例的变量和常量,这意味着,实际上,class级别或class范围