【问题标题】:Correct way of setting Python class attributes设置Python类属性的正确方法
【发布时间】:2018-09-29 03:11:14
【问题描述】:

所以我正在尝试学习如何正确设置 Python 类的 Class 属性,并想知道如何使用类函数来做到这一点。

我的初学者方法教会了我:

class MyClass:
    """MyClass class instance"""
    def __init__(self, project, version, command):
        self.project = project
        self.__version = version
        self.__command = command


    """Get version used"""
    def getVersion(self):
        return self.__version

    """Get command executed"""
    def getCommand(self):
        return self.__command

    """Set version used"""
    def setVersion(self, version):
        self.__version = version

这很好也很简单,但这意味着我在实例化 MyClass 时已经知道我的属性值,因为我传递它们来创建我的对象,或者如果我不传递它们,我会使用我的初学者方式setVersion(version) 创建 MyClass 对象后。在我的搜索中,我读到了this,这让我读到了properties,这让我意识到我不应该在Python 中使用getter/setter,而应该使用属性。它是否正确?

但是,我想知道使用函数设置某些 MyClass 实例属性(项目、版本、命令)是否符合 Pythonic(或者甚至是正确的)。我想这样做是因为我希望这个类通过仅传递 1 个参数来完成从特定文件中查找这些值的工作。想到了这个,但认为它可能是错误的:

class MyClass:
    """MyClass class instance"""
    def __init__(self, project):
        self.project = project
        self._version = self.version()
        self._command = self.command()

    """Get version used"""
    def version(self):
        ...
        use `project` attribute here to get `version` from file...
        ...
        return version

    """Get command executed"""
    def command(self):
        ...
        use `project` attribute here to get `command` from file...
        ...
        return command

通过调用类函数来设置实例变量甚至是一种合乎逻辑的方式吗?

我应该以某些方式使用属性吗?

我是否应该在 MyClass 之外创建一个找到这些值的函数返回一个 MyClass 实例?

有没有更合适的 Pythonic 方式?

我基本上想创建一个包含所有额外信息(版本、命令等)的对象,只需使用 1 个传递的属性对其进行实例化。

提前谢谢你!

【问题讨论】:

  • 直接属性访问优先于简单的 getter 和 setter,它们只是包装访问。
  • 我不应该在 Python 中使用 getter/setter,而应该使用属性。这是正确的吗? 是的,几乎没有理由使用 getter/setter 代替属性。
  • 撇开完整不说,您用来描述函数功能的字符串应该包含在函数中,而不是在方法定义之上。见PEP On doctrings
  • 属性的好处是,如果您直接公开一个属性,并且人们编写像 c = MyClass(); c.version = 3 这样的代码,那么如果您将 version 更改为财产。
  • 感谢 cmets!好的,我将开始学习如何正确使用属性。刚开始学习 Python,在学习一门新语言时,我总是觉得一些基础知识会变成更高级的结构,所以属性是一个不错的发现。

标签: python python-3.x class oop


【解决方案1】:

有很多方法可以解决这个问题,但我通常是这样做的:

class MyClass:
    """MyClass class instance"""
    def __init__(self, project, version, command):
        self.project = project
        self.version = version
        self.command = command

    @classmethod
    def from_file(cls, project):
        """ 
        Alternate constructor that takes a project 
        and extracts the other attributes from a file
        """
        #... some code to use `project` 
        #... and get `version` and `command` from file
        return cls(project, version, command)

# usage
m = MyClass.from_file('project01')

classmethod 是一个装饰器,它使方法能够在类中直接调用,而不是在实例中调用。 然后该方法将自动获取类作为第一个参数。 cls 只是一个表示类的名称,就像我们使用 self 一样,但我们真的可以使用任何名称。 __init__ 中的主要对象构造函数采用完整参数,但新的 from_file 类方法可作为替代构造函数, 通过创建类的实例并返回它。

请注意,这不是一个确定的答案,而只是一个解决问题的pythonic方法的建议。

【讨论】:

  • @classmethod是什么,它有什么特殊意义吗?值得注意的是,cls 是标准约定还是意味着“类”。我假设这是将函数中找到/设置的version 和command 值返回给类......然后创建MyClass 的实例?哪个反过来使我的m 成为对象?
  • @bretonics 您的假设大部分是正确的。我已经编辑了答案并添加了一些解释,可能会解决您的疑问。
【解决方案2】:
  1. 通过在__init__ 中使用关键字变量,您可以灵活地在实例化时只传递一个变量。
  2. 使用诸如@property 和@bar.setter 之类的装饰器使您能够访问和修改相关的属性。而且我相信这也是一种非常 Pythonic 的方式。

以下是我的方法。

class MyClass:
    def __init__(self, project, version=None, command=None):
        self.project = project
        self.__version = version
        self.__command = command

    @property
    def version(self):
        return self.__version

    @version.setter
    def version(self, val):
        self.__version = val

    @property
    def command(self):
        return self.__command

    @command.setter
    def command(self, val):
        self.__command = val

【讨论】:

    猜你喜欢
    • 2012-01-18
    • 1970-01-01
    • 2013-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    • 2019-04-18
    • 1970-01-01
    相关资源
    最近更新 更多