Python 类

发布于 2025-01-19 21:59:09 字数 5191 浏览 1 评论 0

py2 和 py3 的区别

class 声明是否带上 object

# 默认, Python 3
class A:
    pass

# Python 2
class A(object):
    pass

super

通过 super 可以调用父类的方法,避免了重复代码,方便维护,是类继承设计的其中一个目的. super 的简单使用

class MySuper(object):
    def __init__(self,a):
        self.a = a

class MySub(MySuper):
    def __init__(self,a,b):
        self.b = b
        super().__init__(a)

my_sub = MySub(42,'chickenman')
print(my_sub.a)    # 42
print(my_sub.b)    # chickenman
# a 变量的赋值没有放在子类中,而是放在父类中完成

py2 和 py3 中的区别 : python3 中 super() -> same as super(__class__, self) , python2 中则要使用 super(CurrentClass, self)

所以 python3 中可以这样使用 here

class C(B):
    def method(self, arg):
        super().method(arg)    # This does the same thing as:
                               # super(C, self).method(arg)

super 深入

Python: super 没那么简单

单继承

class A:
    def __init__(self):
        self.n = 2

    def add(self, m):
        print('self is {0} @A.add'.format(self))
        self.n += m

class B(A):
    def __init__(self):
        self.n = 3

    def add(self, m):
        print('self is {0} @B.add'.format(self))
        super().add(m)
        self.n += 3

如果运行

b = B()
b.add(2)
print(b.n)

得到的结果如下:

self is <__main__.B object at 0x106c49b38> @B.add
self is <__main__.B object at 0x106c49b38> @A.add
8

多继承

class C(A):
    def __init__(self):
        self.n = 4

    def add(self, m):
        print('self is {0} @C.add'.format(self))
        super().add(m)
        self.n += 4


class D(B, C):
    def __init__(self):
        self.n = 5

    def add(self, m):
        print('self is {0} @D.add'.format(self))
        super().add(m)
        self.n += 5

运行

d = D()
d.add(2)
print(d.n)

输出结果如下

self is <__main__.D object at 0x10ce10e48> @D.add
self is <__main__.D object at 0x10ce10e48> @B.add
self is <__main__.D object at 0x10ce10e48> @C.add
self is <__main__.D object at 0x10ce10e48> @A.add
19

因为此时的 MRO(Method Resolution Order) 列表为 [D, B, C, A, object]

property

通常我们将有实际意义的属性通过函数的方式暴露给用户使用,而不是直接将对象本身传递给用户,这样做可以对参数进行检验,也使得参数更加安全不能被任意的使用者调用,如果使用函数,则对应的 get/set 方法就会变成 Obj.set_attr(value)/Obj.set_attr() .这样对调用者比较不友好,他们更希望的 get/set 方法是 obj.attr=value/obj.attr (和直接调用属性的方式一样)

class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

把一个 getter 方法变成属性,只需要加上 @property 就可以了,此时, @property 本身又创建了另一个装饰器 @score.setter ,负责把一个 setter 方法变成属性赋值,于是,我们就拥有一个可控的属性操作

>>> s = Student()
>>> s.score = 60 # OK,实际转化为 s.set_score(60)
>>> s.score      # OK,实际转化为 s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
  ...
ValueError: score must between 0 ~ 100!

还可以通过 @property 设置只读属性,如下, birth 是可读可写的对象, age 是只读对象

class Student(object):

    @property
    def birth(self):
        return self._birth

    @birth.setter
    def birth(self, value):
        self._birth = value

    @property
    def age(self):
        return 2014 - self._birth

FAQ

init 时如果为 None 设为默认值

不要在类中 __init__ 中使用可变对象作为默认值,如果要使用默认值,应该在 __init__ 中默认值设为 None ,且在函数体中实现可变对象的赋值

class tmp:
    def __init__(self, a, b=None):
        self.a = a
        self.b = b or [] # b or []或选取第一个不为 None 的值

new init 哪个先执行

  • __new__ : 返回一个新的类的实例
  • __init__ : 对类实例进行初始化

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

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

手心的温暖

暂无简介

文章
评论
25 人气
更多

推荐作者

迎风吟唱

文章 0 评论 0

qq_hXErI

文章 0 评论 0

茶底世界

文章 0 评论 0

捎一片雪花

文章 0 评论 0

文章 0 评论 0

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