如何在Python中定义类?

63 投票
3 回答
91086 浏览
提问于 2025-04-15 14:41

很简单,我正在学习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的类,里面有属性:名字/标志/成员

编辑

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

class Team:
    pass

之后

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

这样写是Python的写法吗?感觉有点奇怪(当然是因为我来自一个强类型的语言)。

3 个回答

1

要写一个类,通常你会这样做:

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字典的方式很相似。

122

这是我推荐的做法:

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 3.0 及以上版本中,即使你不写 (object),类也总是“新式”的;不过加上这个写法没有坏处,反而让继承关系更加明确。)这里有一个关于新式类的讨论:Stack Overflow 讨论

  2. 虽然不是必须的,但我让初始化函数可以接收可选参数,这样你可以在一行代码中初始化实例,就像我对 teamteam3 所做的那样。这些参数是有名字的,所以你可以像对 team 那样按位置传值,也可以像对 team3 那样使用 argument= 的形式。当你明确指定参数名时,可以随意顺序传递参数。

  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。(你可以很容易地重载 == 运算符,让 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 设计模式,或者至少是你应该掌握的一种习惯用法。

63
class Team:
  def __init__(self):
    self.name = None
    self.logo = None
    self.members = 0

在Python中,通常你不需要写获取器和设置器,除非你有一些复杂的实现需要这样做(在这种情况下,你可以使用属性描述符)。

撰写回答