需要区分类内外变量

在Python中声明类变量时,通常使用 self 对象的方法,但准确来说这是在实例中使用内部变量的方法。由于访问该类变量需要创建实例,如果需要在所有对象中保证相同值,或者想要达到类似C#或Java等其他语言中 static 关键字的效果,则应在 __init__() 函数外部声明。

class Person:
    ''' 可以如下声明。
    '''
    type = "person"
    
    def __init__(self):
        self.name = name
        self.age  = age
        # ...

该变量在所有实例中提供相同的值。此时需要注意,对该变量的访问,即使在对象内部也需要通过 类名.变量名 的形式进行。例如,在 Person 类内部需要将 type 变量值修改为 another_person_type 时,可以通过 Person.type = another_person_type 访问。

Python也可以使用getter、setter

虽然不叫C#、Java等语言中的 gettersetter,但将类内部变量与公开属性相连接的概念是相同的。虽然对隐藏类内部变量也有用,但更主要的是可以将某个变量值变更时的逻辑连接起来,因此值得了解。

class Example:
    def __init__(self):
        self._variable = None
    
    @property
    def variable(self):
        return self._variable

    @variable.setter(self, value):
        self._variable = value

与其他语言中只声明 getter 时表现为只读一样,如果只声明 @property,尝试修改该属性变量时会报错,需要注意。

模块名可以反映类数量

基本来说,函数是代码的分类单元,类是函数和变量的分类单元,模块是类的分类单元。在概念上更好地实现这一视角的方法之一是,当一个模块中有多个类时,将模块名简单写成复数形式。

myproject/

├── app/
   ├── users/
   ├── models.py
   ├── views.py
   └── controllers.py
   ├── products/
   └── orders/

└── main.py

此时,models.py 中可以使用例如 UserModel()ProductModel() 等名称+类型格式的类名(虽然不是实际项目示例,不够具体)。这种结构相对于一个模块一个类,类的分类更明确,使用模块时还能像 from models import UserModel as UM 这样使用自然的表达。

直观的名称优于比喻

使用比喻时,其直观性大多只算半吊子。那半吊子确实能让初次接触时代码的运行过程更简洁、读起来更有趣,但剩下的那一半会导致编写代码的意图变得模糊,因此我认为应尽量避免。

def main():
    ''' 以宝石工匠为主题的话,大致这样
    '''
    self.mining()  
    self.cutting() 
    self.crafting()
    self.selling()

def main()
    ''' 以高级料理主厨为主题的话,大致这样
    '''
    self.washing()
    self.cutting()
    self.cooking()
    self.plating()

虽然曾尝试用各种比喻手法来结构化代码——比如以上述方式,以宝石销售为主题,将过程比喻为采矿-切割-加工-售卖;或者模仿厨师做菜的过程,采用清洗-切配-烹饪-摆盘的结构——但经过比喻的函数名未能清晰反映代码的作用。

因此,理解含义的过程中多了一个步骤,导致他人或未来的自己阅读代码时,在直观理解意义上产生了不必要的困难,有时甚至出现主客颠倒,有意识地考虑类与函数所拥有的主题来编写代码的情况。

相反,虽然少了些趣味,但按照标准方式编写类的职责会更简洁。

def main():
    ''' 就是一般情况
    '''
    download_data()
    basic_process()
    save_results()

如果借用成语或著名典故等比喻,辅助观念的直观性很强时,或许还不错;但除此之外的大部分情况下,像上述那样简洁描述代码本身的操作更为实用。