最“Pythonic” 组织类属性、构造函数参数和子类构造函数默认值的方式?

发布于 2024-07-27 12:17:58 字数 2525 浏览 4 评论 0原文

作为 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 语言为了让事情看起来更加直观和明显而花费的篇幅,在我有很多属性或很多默认构造函数参数的少数情况下,这对我来说似乎非常奇怪,尤其是当我我正在子类化:

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”方式是什么? 如果默认值是不可变的(ala Pants.pockets),最好将它们放在类中,还是最好将它们放在构造函数中(ala ClassWithLotsOfAttributes.noisiness)?

  • 是否有一种方法可以消除重新声明所有子类构造函数参数的默认值的需要,如 Dog.__init__ 中那样? 无论如何,我是否应该包含这么多带有默认值的参数?

Being relatively new to Python 2, I'm uncertain how best to organise my class files in the most 'pythonic' way. I wouldn't be asking this but for the fact that Python seems to have quite a few ways of doing things that are very different to what I have come to expect from the languages I am used to.

Initially, I was just treating classes how I'd usually treat them in C# or PHP, which of course made me trip up all over the place when I eventually discovered the mutable values gotcha:

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

Yikes! Didn't expect that!

I've spent a lot of time searching the web and through some source for other projects for hints on how best to arrange my classes, and one of the things I noticed was that people seem to declare a lot of their instance variables - mutable or otherwise - in the constructor, and also pile the default constructor arguments on quite thickly.

After developing like this for a while, I'm still left scratching my head a bit about the unfamiliarity of it. Considering the lengths to which the python language goes to to make things seem more intuitive and obvious, it seems outright odd to me in the few cases where I've got quite a lot of attributes or a lot of default constructor arguments, especially when I'm subclassing:

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"

Mild silliness aside (I can't really help myself when cooking up these artificial example classes), assuming I have a real-world need for a set of classes with this many attributes, I suppose my questions are:

  • What is the most, uhh, 'pythonic' way of declaring a class with that many attributes? Is it best to put them against the class if the default is immutable, ala Pants.pockets, or is it better to put them in the constructor, ala ClassWithLotsOfAttributes.noisiness?

  • Is there a way to eliminate the need to redeclare the defaults for all of the subclass constructor arguments, as in Dog.__init__? Should I even be including this many arguments with defaults anyway?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

汐鸠 2024-08-03 12:17:58
  • 如果属性因实例而异
    实例化 让它们实例化
    属性,即创建它们
    __init__内部使用self,否则如果他们需要的话
    在类实例之间共享
    像常数一样,把它们放在课堂上
    级别。

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

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

  • 如果您需要向 Dog 和关键字 arg old 添加额外的参数咬合

class CoolDog(ClassWithLotsOfAttributes):
    def __init__(self, bite, *args , **kwargs):
        self.old = kwargs.pop('old', False) # this way we can access base class args too
        super(ClassWithLotsOfAttributes,    self).__init__(*args , **kwargs)
        self.bite = bite
        self.coolness = "really really cool!!!

您可以使用 CoolDog 的各种方式

CoolDog(True)
CoolDog(True, old=False)
CoolDog(bite=True, old=True)
CoolDog(old=True, bite=False)
  • If attributes will vary from instance
    to instance make them instance
    attribute i.e. create them
    inside__init__ using self else if they need to
    be shared between class instances
    like a constant, put them at class
    level.

  • If your class really need to pass, so
    many arguments in __init__, let
    derive class use argument list and
    keyword arguments e.g.

class Dog(ClassWithLotsOfAttributes):
    def __init__(self, *args , **kwargs):
        super(ClassWithLotsOfAttributes,    self).__init__(*args , **kwargs)
        self.coolness = "really cool!!!
  • No need of passing all variables except few important ones, in
    __init__, class can assume some
    defaults and user can change them
    later on if needed.
  • Use 4 spaces instead of tab.

  • if you need to add an extra arg bite, to Dog and keyword arg old too

class CoolDog(ClassWithLotsOfAttributes):
    def __init__(self, bite, *args , **kwargs):
        self.old = kwargs.pop('old', False) # this way we can access base class args too
        super(ClassWithLotsOfAttributes,    self).__init__(*args , **kwargs)
        self.bite = bite
        self.coolness = "really really cool!!!

various ways you useCoolDog

CoolDog(True)
CoolDog(True, old=False)
CoolDog(bite=True, old=True)
CoolDog(old=True, bite=False)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文