代码之家  ›  专栏  ›  技术社区  ›  OscarRyz

如何在Python中定义类?

  •  49
  • OscarRyz  · 技术社区  · 15 年前

    很简单,我正在学习python,找不到一个可以告诉我如何编写以下内容的引用:

    public class Team {
         private String name;
         private String logo;
         private int members;
    
         public Team(){}
    
         // getters/setters 
     }
    

    后来:

    Team team = new Team();
    team.setName( "Oscar" );
    team.setLogo( "http://...." );
    team.setMembers( 10 );
    

    这是一个具有以下属性的类团队:name/logo/members

    编辑 经过几次尝试,我得到了:

    class Team:
        pass
    

    以后

    team = Team()
    team.name="Oscar"
    team.logo="http://..."
    team.members=10
    

    这是蟒蛇道吗??感觉很奇怪(当然是来自强类型语言)

    2 回复  |  直到 6 年前
        1
  •  49
  •   Martin v. Löwis    15 年前
    class Team:
      def __init__(self):
        self.name = None
        self.logo = None
        self.members = 0
    

    在Python中,通常不编写getter和setter,除非您确实有一个非常重要的实现(此时使用属性描述符)。

        2
  •  103
  •   Community CDub    8 年前

    以下是我的建议:

    class Team(object):
        def __init__(self, name=None, logo=None, members=0):
            self.name = name
            self.logo = logo
            self.members = members
    
    team = Team("Oscar", "http://...", 10)
    
    team2 = Team()
    team2.name = "Fred"
    
    team3 = Team(name="Joe", members=10)
    

    关于这个的一些注释。

    0)我声明团队继承自 object . 这使团队成为“新风格的类”;自从Python2.2中引入以来,这是Python中的推荐实践。(在python 3.0及更高版本中,类总是“新样式”,即使您不考虑 (object) 表示法;但是使用该表示法不会造成损害,并且使继承显式化。)这里有一个stackoverflow discussion 新风格的课程。

    1)这不是必需的,但我让初始值设定项采用可选参数,以便您可以在一行上初始化实例,就像我使用的那样 team team3 .这些参数是命名的,因此您可以将值作为位置参数(与 团队 )或者你可以使用 argument= 就像我做的那样 团队3 . 显式指定参数名称时,可以按任意顺序指定参数。

    2)如果需要getter和setter函数,也许需要检查一些东西,那么可以在python中声明特殊的方法函数。这就是马丁诉路易斯案中所说的“财产描述符”的意思。在Python中,通常认为简单地分配给成员变量并简单地引用它们来获取它们是一种良好的实践,因为如果您以后需要的话,可以随时添加属性描述符。(如果你从不需要它们,那么你的代码就不那么杂乱了,你花的时间也更少了。奖金!)

    以下是关于属性描述符的一个很好的链接: http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/

    3)如果将值指定为 Team() 或者稍后将它们插入类实例中。最终使用的类实例将是相同的。

    team = Team("Joe", "http://example.com", 1)
    team2 = Team()
    team2.name = "Joe"
    team2.logo = "http://example.com"
    team2.members = 1
    
    print team.__dict__ == team2.__dict__
    

    上面将打印 True . (你可以很容易地超载 == 算子 Team 实例,并使python在您说 team == team2 但这在默认情况下不会发生。)


    编辑:我在上面的答案中遗漏了一件事,现在我想添加它。如果您在 __init__() 函数,如果要提供“可变”作为可选参数,则需要小心。

    整数和字符串是“不变的”。您永远不能在适当的地方更改它们;相反,会发生的事情是,Python创建一个新对象并替换您以前拥有的对象。

    列表和字典是“可变的”。您可以永远保留同一个对象,添加到该对象并从中删除。

    x = 3   # the name "x" is bound to an integer object with value 3
    x += 1  # the name "x" is rebound to a different integer object with value 4
    
    x = []  # the name "x" is bound to an empty list object
    x.append(1)  # the 1 is appended to the same list x already had
    

    您需要知道的关键一点是:在编译函数时,可选参数只计算一次。因此,如果在 γ-iITI^() 对于类,则类的每个实例共享一个可变对象。这几乎不是你想要的。

    class K(object):
        def __init__(self, lst=[]):
            self.lst = lst
    
    k0 = K()
    k1 = K()
    
    k0.lst.append(1)
    
    print k0.lst  # prints "[1]"
    print k1.lst  # also prints "[1]"
    
    k1.lst.append(2)
    
    print k0.lst  # prints "[1, 2]"
    

    解决方案非常简单:

    class K(object):
        def __init__(self, lst=None):
            if lst is None:
                self.lst = []  # bind lst with a new, empty list
            else:
                self.lst = lst # bind lst with provided list
    
    k0 = K()
    k1 = K()
    
    k0.lst.append(1)
    
    print k0.lst  # prints "[1]"
    print k1.lst  # print "[]"
    

    使用默认参数值 None ,然后测试参数是否通过 is None ,可以作为Python设计模式,或者至少是您应该掌握的习惯用法。