Python - 定义仅使用一次的常量变量的最方便的方法

时间:2016-01-11 11:28:02

标签: python coding-style pyqt convention pep

假设我有一个文件“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"

3 个答案:

答案 0 :(得分:5)

经验法则

  • 一般情况下,你应该避免全局变量,因为它们存在于内存中,因为你导入模块直到程序结束(第一种情况)
  • 通常,您应该避免在函数内部修复值(第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种方式 - 作为类级别恒定即可。
  • 如果您想要实例级别常量或变量,则应使用 2dn经验法则

第三种方式 - 在方法中定义<\ strong>

  • 你应该避免这种方式支持第二经验法

第4路 - 作为班级常数

  • 仅针对共享同一类的所有实例的变量和常量的推荐方式,实际上意味着类级别类范围

答案 1 :(得分:4)

将它们定义为类变量可能是最具前瞻性的方法,因为您稍后可以使用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')

关于吸气者的说明:安装者:

另请注意,Python中应避免使用getter和setter,如果需要验证,则使用properties代替,或者重构具有大量相关代码的类。在Java和C等预编译语言中,getter / setter用于封装,以便以后可以更改实现,但是在Python中避免了性能和清晰度。首先,变量可以正常访问,如果实现发生变化,您可以使用@property@variable.setter装饰器,以便使用getter和setter,即使您似乎正在访问变量直接。

因此,您最初可以直接访问icon

print(server.icon)

但是我们稍后会说,您将课程内的icon重构为_icon_file_icon_image,并在每次设置时加载文件,但应用的其余部分期待icon变量。这是getters和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

答案 2 :(得分:2)

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

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