【问题标题】:Most "pythonic" way of organising class attributes, constructor arguments and subclass constructor defaults?组织类属性、构造函数参数和子类构造函数默认值的最“pythonic”方式?
【发布时间】:2010-11-10 05:17:18
【问题描述】:

作为 Python 2 的新手,我不确定如何以最“pythonic”的方式最好地组织我的类文件。我不会问这个,但事实上 Python 似乎有很多做事的方式与我对我习惯的语言所期望的非常不同。

最初,我只是按照我通常在 C# 或 PHP 中对待它们的方式处理类,当我最终发现可变值陷阱时,这当然让我四处走动:

class Pants(object):
    pockets = 2
    pocketcontents = []

class CargoPants(Pants):
    pockets = 200

p1 = Pants()
p1.pocketcontents.append("Magical ten dollar bill")
p2 = CargoPants()

print p2.pocketcontents

哎呀!没想到!

我花了很多时间在网上搜索并通过其他项目的一些资源来寻找如何最好地安排我的课程的提示,我注意到的一件事是人们似乎声明了很多他们的实例变量- 可变或其他 - 在构造函数中,并且还将默认构造函数参数堆得很厚。

在这样发展了一段时间后,我仍然对它的不熟悉感到有些摸不着头脑。考虑到 python 语言使事情看起来更直观和明显的长度,在我有很多属性或很多默认构造函数参数的少数情况下,这对我来说似乎完全奇怪,尤其是当我'm 子类化:

class ClassWithLotsOfAttributes(object):
    def __init__(self, jeebus, coolness='lots', python='isgoodfun', 
             pythonic='nebulous', duck='goose', pants=None, 
             magictenbucks=4, datawad=None, dataload=None,
             datacatastrophe=None):

        if pants is None: pants = []
        if datawad is None: datawad = []
        if dataload is None: dataload = []
        if datacatastrophe is None: datacatastrophe = []
        self.coolness = coolness
        self.python = python
        self.pythonic = pythonic
        self.duck = duck
        self.pants = pants
        self.magictenbucks = magictenbucks
        self.datawad = datawad
        self.dataload = dataload
        self.datacatastrophe = datacatastrophe
        self.bigness = None
        self.awesomeitude = None
        self.genius = None
        self.fatness = None
        self.topwise = None
        self.brillant = False
        self.strangenessfactor = 3
        self.noisiness = 12
        self.whatever = None
        self.yougettheidea = True

class Dog(ClassWithLotsOfAttributes):
    def __init__(self, coolness='lots', python='isgoodfun', pythonic='nebulous', duck='goose', pants=None, magictenbucks=4, datawad=None, dataload=None, datacatastrophe=None):
        super(ClassWithLotsOfAttributes, self).__init__(coolness, python, pythonic, duck, pants, magictenbucks, datawad, dataload, datacatastrophe)
        self.noisiness = 1000000

    def quack(self):
        print "woof"

除了有点愚蠢(在制作这些人工示例类时我真的无法自拔),假设我在现实世界中需要一组具有这么多属性的类,我想我的问题是:

  • 声明具有这么多属性的类的最“pythonic”方式是什么?如果默认值是不可变的,比如 Pants.pockets,最好将它们放在类中,还是将它们放在构造函数中,比如 ClassWithLotsOfAttributes.noisiness 更好?

  • 有没有办法消除重新声明所有子类构造函数参数的默认值的需要,就像在 Dog.__init__ 中一样?我是否应该在默认值中包含这么多参数?

【问题讨论】:

  • +1 一定会喜欢你的示例属性。还有,好问题。

标签: python python-2.6


【解决方案1】:
  • 如果属性因实例而异 实例化它们 属性,即创建它们 inside__init__ 使用 self else if they need to 在类实例之间共享 像一个常数,把它们放在课堂上 级别。

  • 如果你的课真的需要通过,那么 __init__ 中有很多参数,让 派生类使用参数列表和 关键字参数,例如

类狗(ClassWithLotsOfAttributes):
    def __init__(self, *args, **kwargs):
        super(ClassWithLotsOfAttributes, self).__init__(*args , **kwargs)
        self.coolness = "真的很酷!!!
  • 不需要传递除少数重要变量外的所有变量,在 __init__,类可以假设一些 默认值,用户可以更改它们 如果需要,稍后再做。
  • 使用 4 个空格代替制表符。

  • 如果您需要添加额外的 arg 咬合,也可以添加到 Dog 和关键字 arg old

类 CoolDog(ClassWithLotsOfAttributes):
    def __init__(self, bit, *args, **kwargs):
        self.old = kwargs.pop('old', False) # 这样我们也可以访问基类 args
        super(ClassWithLotsOfAttributes, self).__init__(*args , **kwargs)
        self.bite = 咬
        self.coolness = "真的很酷!!!

你使用酷狗的各种方式

CoolDog(True)
CoolDog(True, old=False)
CoolDog(bite=True, old=True)
CoolDog(old=True, bite=False)

【讨论】:

  • 哦,我不知道你可以这样使用 *args 和 **kwargs! “酷”绝对需要升级为“真的很酷!!!” :)
  • 另外,Dog.__init__ 需要添加额外的构造函数参数的情况如何? def__init__(self,legs=4, *args, **kwargs) 是正确的方法吗?
  • 是的,你可以专门检查 kargs 中的 var name,我将添加一个示例
  • “使它们成为实例属性,即在__init__ 中创建它们” -> 真正重要的是使用self 而不是类。我认为这可能会误导初学者。
  • 没有区别,您可以实际使用它,但我添加了 pop 以便您在需要时也可以实际访问基类参数
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-24
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
  • 2016-03-24
相关资源
最近更新 更多