【问题标题】:Python - most convenient way to define constant variables used just once [closed]Python - 定义只使用一次的常量变量的最方便方法[关闭]
【发布时间】:2016-04-15 16:39:26
【问题描述】:

假设我有一个文件“icon.ico”和一个网址“url.com”。
在类中只使用一次 - “icon.ico”将设置为某个窗口,我们将通过一种方法对 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

第二种方式 - 定义为类的变量

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"

【问题讨论】:

  • 您对此有何看法?例如 .ini 文件什么时候才有意义?
  • @fafl 现在我使用第一种方式,我只是想知道它是否方便)
  • 如果这些变量是相对于特定类的,我会将它们声明为静态成员,而不是像您在第二种方式中建议的实例成员。
  • 您的问题是什么?因此,这个问题目前还不够具体。这三种方法都是可行的。您选择哪一个将取决于大局是什么——您还需要对这些变量做些什么,等等。
  • PEP8 并不是一个真正的意见,而是一个风格指南:python.org/dev/peps/pep-0008/#constants 并为常量定义了一个结构(这是你的#1)

标签: python coding-style pyqt convention pep


【解决方案1】:

经验法则

  • 一般来说,您应该避免使用全局变量,因为它们会一直存在于内存中,因为您导入模块直到程序完成(第一种情况)
  • 一般来说,您应该避免在函数内固定值(第 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

何时使用每种情况的提示

第一种方式 - 定义为全局常量

  • 该常量具有作为模块范围常量的意义。请记住,可以在同一个模块中声明多个类和函数。这意味着该常量将在整个模块中使用,并且不属于任何特定类。
  • 您需要快速找到常数,通常是更改其值。在这种情况下,您可能并不需要一个常量,而是一个变量。

第二种方式 - 定义为类的变量

  • 如果是类的变量,则不是常量。如果您想使用类的常量或变量(在类级别而不是实例级别),您应该使用 4-th 方式 - 作为类级别恒定
  • 如果您想要实例级常量或变量,您应该使用 2dn 经验法则

第三种方式 - 仅在将要使用的方法中定义

  • 您应该避免这种方式,以支持第二条经验法则

4-th way - 作为类级常量

  • 推荐的方式仅适用于共享同一类的所有实例的变量和常量,实际上是指类级别类范围

【讨论】:

    【解决方案2】:

    将它们定义为类变量可能是最面向未来的方法,因为您以后可以使用dependency injection 来更改这些变量,这对于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 代替,或者重构具有大量依赖代码的类。在 Java 和 C 等预编译语言中,getter/setter 用于封装,以便以后可以更改实现,但在 Python 中为了性能和清晰度而避免使用。因此,首先,可以正常访问变量,如果实现发生变化,您可以使用 @property@variable.setter 装饰器,以便使用 getter 和 setter,即使您似乎是直接访问变量。

    原来你可以直接访问icon

    print(server.icon)
    

    但是让我们稍后说您将类中的 icon 重构为 _icon_file_icon_image 并在每次设置文件时加载文件,但应用程序的其余部分需要 icon 变量。这就是 getter 和 setter 通常的用途(以及对设置变量的任何检查/转换),因此我们现在可以为 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
    

    【讨论】:

      【解决方案3】:

      您忘记了将它们定义为类级常量的选项:

      class Foo(...)
          ICON = "xxx"
          URL = "YYY"
      

      【讨论】:

        猜你喜欢
        • 2018-11-05
        • 2012-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-15
        • 1970-01-01
        • 2017-06-11
        • 2015-12-26
        相关资源
        最近更新 更多