【问题标题】:How can I define a class in Python?如何在 Python 中定义一个类?
【发布时间】:2010-12-02 12:18:24
【问题描述】:

很简单,我正在学习 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);

这是一个类 Team,具有以下属性:name/logo/members

编辑

经过几次尝试,我得到了这个:

class Team:
    pass

稍后

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

这是 Python 的方式吗?感觉很奇怪(当然来自强类型语言)。

【问题讨论】:

  • 我想建议有人将标题更改为更适合将来搜索的内容。类似于“在 Python 中定义类的最佳方式”。
  • @steveha:虽然我真正的问题是,我该如何在 python 中编写这个......那么......

标签: python


【解决方案1】:

以下是我的建议:

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)

对此的一些说明:

  1. 我声明Team 继承自object。这使得Team成为一个“新式班”;自从它在 Python 2.2 中引入以来,这一直是 Python 中的推荐做法。 (在 Python 3.0 及更高版本中,即使您省略了 (object) 表示法,类也始终是“新式”;但使用该表示法并没有害处,并且使继承变得明确。)这是一个堆栈溢出 discussion 的 new-样式类。

  2. 这不是必需的,但我让初始化程序采用可选参数,以便您可以在一行上初始化实例,就像我对 teamteam3 所做的那样。这些参数是命名的,因此您可以提供值作为位置参数(如team),也可以使用argument= 形式,就像我对team3 所做的那样。显式指定参数名称时,可以按任意顺序指定参数。

  3. 如果你需要 getter 和 setter 函数,也许是为了检查一些东西,在 Python 中你可以声明特殊的方法函数。这就是 Martin v. Löwis 在说“财产描述符”时的意思。在 Python 中,通常认为简单地分配给成员变量并简单地引用它们以获取它们是一种很好的做法,因为您可以随时在以后需要时添加属性描述符。 (如果您从不需要它们,那么您的代码就不会那么混乱,并且花费您更少的时间来编写。奖金!)

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

注意:Adam Gomaa 的博客似乎已从网络上消失。这是 archive.org 上已保存副本的链接:

https://web.archive.org/web/20160407103752/http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/

  1. 在调用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

您需要知道的关键点:可选参数仅在编译函数时计算一次。因此,如果您在类的__init__() 中将可变参数作为可选参数传递,那么类的每个实例都会共享一个可变对象。这几乎不是你想要的。

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 the provided list

k0 = K()
k1 = K()

k0.lst.append(1)

print(k0.lst)  # prints "[1]"
print(k1.lst)  # prints "[]"

使用默认参数值None,然后测试该参数是否通过is None,这符合 Python 设计模式,或者至少是您应该掌握的习语。

【讨论】:

  • 如果您希望字符串的默认值为 "" 而不是 None,您可以在 __init__() 函数中进行更改。
  • +1 有趣:如果使用命名参数,我不会得到“方法init使用正好4个参数使用0”错误消息?? ...
  • @Oscar Reyes:不。如果为它们提供了默认值,则这些参数是可选的。
  • 我喜欢超越原始问题的清晰详细的讨论。非常感谢
  • adam.gomaa.us 链接似乎已损坏(域不存在?)。
【解决方案2】:
class Team:
  def __init__(self):
    self.name = None
    self.logo = None
    self.members = 0

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

【讨论】:

  • Martin,我的发现 class Team:pass 和你的样本有什么区别?
  • 您可以根据需要动态添加属性,但如果 Team 类将始终包含这些属性,则更清楚的是在类内部而不是外部定义它们。
  • 它对文档很有用,因为它可以让查看您的课程的人看到哪些属性有用。
  • 主要区别在于Team()之后,你已经将name、log、members设置为一些默认值;对于空类,您最初没有设置任何属性。您通常会避免稍后添加属性并将它们全部设置在构造函数中,以便您可以相信它们存在于所有方法中。但是,您也尽可能尝试将它们初始化为正确的值(来自构造函数参数),就像在 Java 中所做的那样。
  • @Pynt,怎么会这样?对我来说看起来相当标准,所以如果有一些人们应该避免的事情,你能为我们详细说明一下吗?
【解决方案3】:

编写你通常会做的类:

class Person:
    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height

要实例化一个类的实例,你会这样做

person1 = Person("Oscar", 40, "6ft")

person2 = Team("Danny", 12, "5.2ft")

你也可以设置一个默认值:

 class Person:
        def __init__(self):
            self.name = "Daphne"
            self.age = 20
            self.height = "5.4ft"

要像这样实例化一个类集,您需要这样做:

person3 = Person()
person3.name = "Joe"
person3.age = 23
person3.height = "5.11ft"

你会注意到这个方法与你典型的 Python 字典交互有很多相似之处。

【讨论】:

    猜你喜欢
    • 2014-12-20
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    • 2014-12-02
    • 2012-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多