当前位置:首页 > 技术 > 正文内容

Python内置方法详解(下)

访客 技术 2026年7月29日 3

六、property属性

概述

property()函数是创建数据描述符的一种简洁方式,它允许在访问对象属性时自动触发函数调用。其函数签名如下:

property(fget=None, fset=None, fdel=None, doc=None) -> property attribute

属性是一种特殊类型的描述符,用于处理对实例属性的所有访问操作。property()函数接受若干函数作为参数,这些参数实际上是类定义中的方法。当类被创建时,property()会被调用,而这些作为参数的方法是非绑定的函数。

定义方式

属性的定义有两种主要方式:

  • 装饰器方式:在方法上应用@property装饰器
  • 类属性方式:在类中定义值为property对象的类属性

经典类与新式类的区别

经典类(不继承object)只有一种@property装饰器,而新式类(继承object)支持三种装饰器:@property、@property名.setter、@property名.deleter。

经典类示例:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Product:
    @property
    def price(self):
        return "test"

# 调用
obj = Product()
result = obj.price  # 自动执行 @property 修饰的 price 方法
print(result)

执行结果:

test

新式类示例:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Product(object):

    @property
    def price(self):
        print('执行获取方法')

    @price.setter
    def price(self, value):
        print('执行设置方法')

    @price.deleter
    def price(self):
        print('执行删除方法')

# 调用
obj = Product()

obj.price          # 自动执行 @property 修饰的方法

obj.price = 123    # 自动执行 @price.setter 修饰的方法

del obj.price      # 自动执行 @price.deleter 修饰的方法

执行结果:

执行获取方法
执行设置方法
执行删除方法

完整示例:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Product(object):

    def __init__(self):
        # 原价
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 实际价格 = 原价 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self):
        del self.original_price

obj = Product()
print(obj.price)         # 获取商品价格
obj.price = 200   # 修改商品原价

执行结果:

80.0

类属性方式

使用类属性方式创建属性时,经典类和新式类没有区别:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Student(object):

    def get_name(self):
        return 'zhangsan'

    NAME = property(get_name)

obj = Student()
result = obj.NAME        # 自动调用get_name方法
print(result)

执行结果:

zhangsan

property构造方法的四个参数说明:

  1. 第一个参数是方法名,访问 属性 时自动触发执行
  2. 第二个参数是方法名,给 属性 赋值时自动触发执行
  3. 第三个参数是方法名,删除 属性 时自动触发执行
  4. 第四个参数是字符串,是该属性的描述信息
#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Person:

    def get_age(self):
        return 25

    def set_age(self, value):
        return value + 10

    def del_age(self):
        return 'deleted'

    AGE = property(get_age, set_age, del_age, '年龄描述信息')

obj = Person()

print(obj.AGE)             # 自动调用第一个参数中定义的方法
obj.AGE = 30     # 自动调用第二个参数中定义的方法
print(obj.AGE)     # 获取第四个参数中设置的值

执行结果:

25
40

实际应用案例

分页功能的实现:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Pager:

    def __init__(self, current_page):
        self.current_page = current_page
        self.per_items = 10

    @property
    def start(self):
        val = (self.current_page - 1) * self.per_items
        return val

    @property
    def end(self):
        val = self.current_page * self.per_items
        return val

p = Pager(1)
print(p.start) # 起始值
print(p.end)   # 结束值

执行结果:

0
10

案例:属性类型检查

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class User(object):
    def __init__(self, name):
        self.name = name  # 实例化就触发property

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError('必须是字符串类型')
        self._name = value

    @name.deleter
    def name(self):
        del self._name


user = User('admin')
print(user.name)
user.name = 'guest'
print(user.name)

七、__setitem__、__getitem__、__delitem__

方法说明

  • __getitem__(self, key): 返回键对应的值,obj['key'] 时触发
  • __setitem__(self, key, value): 设置给定键的值,obj['key'] = value 时触发
  • __delitem__(self, key): 删除给定键对应的元素,del obj['key'] 时触发

示例一

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Cache(object):
    def __getitem__(self, item):
        print("__getitem__被调用,key=%s" % item)

    def __setitem__(self, key, value):
        print("__setitem__被调用,key=%s, value=%s" % (key, value))

    def __delitem__(self, key):
        print("__delitem__被调用,key=%s" % key)

obj = Cache()
result = obj['data1']      # 自动触发执行 __getitem__
obj['data2'] = 'hello'   # 自动触发执行 __setitem__
del obj['data1']           # 自动触发执行 __delitem__

执行结果:

__getitem__被调用,key=data1
__setitem__被调用,key=data2, value=hello
__delitem__被调用,key=data1

示例二:通过字典方式操作实例属性

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class User(object):
    def __init__(self, name):
        self.name = name

    def __getitem__(self, item):
        return self.__dict__[item]

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __delitem__(self, key):
        del self.__dict__[key]


u = User('tom')
u['age'] = 25
u['city'] = 'Beijing'
print(u.name)
print(u['age'])
print(u['city'])
print(u.__dict__)

执行结果:

tom
25
Beijing
{'name': 'tom', 'age': 25, 'city': 'Beijing'}

自定义列表类:让下标从1开始

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class MyList(list):

    def __getitem__(self, offset):
        return list.__getitem__(self, offset - 1)

if __name__ == "__main__":
    alist = MyList([10, 20, 30])
    print(alist[1])  # 返回列表的第0项,即10
    print(alist[2])  # 返回列表的第1项,即20
    print(alist[0])  # 返回最后一项,即30

执行结果:

10
20
30

八、__str__、__repr__、__format__

__str__和__repr__

__str__:控制print函数打印返回值,返回值必须是字符串类型
__repr__:控制返回值,返回值必须是字符串类型
当__str__未定义时,会使用__repr__来替代输出

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def __repr__(self):
        return 'Employee: %s, Salary: %d' % (self.name, self.salary)


emp = Employee('zhangsan', 8000)
print(emp)   # 打印对象时调用 __repr__
print(str(emp))  # str函数调用 __str__,如果__str__未定义则调用__repr__
print(repr(emp))  # repr函数调用 __repr__

Time类格式化示例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Time(object):
    def __init__(self, hour, minute):
        self.hour = hour
        self.minute = minute

    def __str__(self):
        return '%02d:%02d' % (self.hour, self.minute)


time1 = Time(9, 30)
time2 = Time(14, 45)
print(time1, time2)

执行结果:

09:30 14:45

__format__方法

__format__方法允许自定义对象的格式化输出:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

format_map = {
    'ymd': '{0.year}-{0.month}-{0.day}',
    'mdy': '{0.month}/{0.day}/{0.year}',
    'dmy': '{0.day}.{0.month}.{0.year}'
}

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def __format__(self, format_spec):
        if not format_spec or format_spec not in format_map:
            format_spec = 'ymd'
        return format_map[format_spec].format(self)


d1 = Date(2023, 8, 15)
print(format(d1, 'ymd'))
print(format(d1, 'mdy'))
print(format(d1, 'dmy'))

执行结果:

2023-8-15
8/15/2023
15.8.2023

九、__next__和__iter__实现迭代器协议

迭代器概念

在Python中,迭代有两个核心概念:

  • Iterable(可迭代对象):实现了__iter__()方法的对象
  • Iterator(迭代器):同时实现了__iter__()和__next__()方法的对象

迭代器协议的规则:

  • __iter__方法返回迭代器本身
  • __next__方法返回下一个迭代对象,迭代结束抛出StopIteration异常

迭代器实现示例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Counter:
    def __init__(self, start, stop):
        self.current = start
        self.stop = stop

    def __iter__(self):
        return self

    def __next__(self):
        if self.current >= self.stop:
            raise StopIteration
        value = self.current
        self.current += 1
        return value


for i in Counter(1, 5):
    print(i)

执行结果:

1
2
3
4

验证迭代器类型:

from collections import Iterable, Iterator

print(isinstance(Counter(1, 5), Iterator))
print(isinstance([1, 2, 3], Iterable))

斐波那契数列迭代器

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Fib:
    def __init__(self):
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        return self.a


f = Fib()
print(next(f))
print(next(f))
print(next(f))

for i in f:
    if i > 100:
        break
    print(i, end=' ')

模拟range函数(带步长)

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Range:
    def __init__(self, start, stop, step=1):
        self.start = start
        self.stop = stop
        self.step = step

    def __iter__(self):
        return self

    def __next__(self):
        if self.start >= self.stop:
            raise StopIteration
        value = self.start
        self.start += self.step
        return value


for i in Range(0, 10, 2):
    print(i, end=' ')

执行结果:

0 2 4 6 8

十、__doc__

__doc__属性用于存储类的描述信息:

class Animal:
    '''这是一个动物类'''
    pass

print(Animal.__doc__)

注意:__doc__属性无法被继承

class Animal:
    '''动物基类'''
    pass

class Dog(Animal):
    pass

print(Dog.__doc__)  # 输出 None

十一、__module__和__class__

  • __module__:表示当前操作的对象所在的模块
  • __class__:表示当前操作的对象的类
# lib/user.py
class User:
    def __init__(self):
        self.name = 'admin'

# index.py
from lib.user import User

obj = User()
print(obj.__module__)  # 输出 lib.user
print(obj.__class__)   # 输出 lib.user.User
class Person:
    def __init__(self):
        self.name = 'person'

obj = Person()
print(obj.__module__)  # 在当前文件执行时输出 __main__
print(obj.__class__)   # 输出 <class '__main__.Person'>

十二、__del__

__del__是析构方法,当对象在内存中被释放时自动触发执行。

如果产生的对象仅在Python程序级别(用户级),则无需定义__del__;如果对象需要管理系统资源(如打开文件、创建数据库连接),则必须在对象删除前回收系统资源。

class Database:
    def __init__(self, name):
        self.name = name
        print('数据库 %s 连接成功' % name)

    def __del__(self):
        print('数据库 %s 连接已关闭' % self.name)


db = Database('mydb')
del db
print('后续代码继续执行')

执行结果:

数据库 mydb 连接成功
数据库 mydb 连接已关闭
后续代码继续执行

重要说明:

class FileHandler:
    def __del__(self):
        print('析构方法被调用')

f = FileHandler()
print('程序即将结束')
# 程序结束时Python会回收用户空间内存,然后自动调用__del__

典型应用场景:文件操作

# 正确方式
f = open('test.txt', 'r')
content = f.read()
f.close()

# 使用with语句(推荐)
with open('test.txt', 'r') as f:
    content = f.read()

十三、__enter__和__exit__

上下文管理协议

为了使对象支持with语句,必须在类的__enter__和__exit__方法中实现相应逻辑。

class FileManager:
    def __init__(self, filename):
        self.filename = filename

    def __enter__(self):
        print('进入with语句块,__enter__被调用')
        self.file = open(self.filename, 'w')
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('离开with语句块,__exit__被调用')
        self.file.close()
        return True


with FileManager('test.txt') as f:
    f.write('Hello World')
    print('正在写入文件')

执行结果:

进入with语句块,__enter__被调用
正在写入文件
离开with语句块,__exit__被调用

异常处理

__exit__方法的三个参数分别代表异常类型、异常值和追溯信息。如果__exit__返回True,异常会被吞掉,程序继续执行。

class Manager:
    def __enter__(self):
        print('enter')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exc_type:', exc_type)
        print('exc_val:', exc_val)
        print('exc_tb:', exc_tb)
        return True  # 吞掉异常


with Manager() as m:
    raise ValueError('发生错误了')
print('程序继续执行')

执行结果:

enter
exc_type: <class 'ValueError'>
exc_val: 发生错误了
exc_tb: ...
程序继续执行

with语句的用途:自动管理资源,无需手动干预清理工作。


十四、__call__

__call__方法允许对象像函数一样被调用。构造方法__init__的执行是由创建对象触发的,而__call__方法的执行是由对象后加括号触发的。

class Calculator:
    def __init__(self, value):
        self.value = value

    def __call__(self):
        return self.value * 2


calc = Calculator(10)
print(calc())  # 调用__call__方法

执行结果:

20

综合示例:__str__和__call__

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __str__(self):
        return self.title

    def __call__(self):
        print('%s 的作者是 %s' % (self.title, self.author))


if __name__ == "__main__":
    book = Book("Python编程", "Zhang San")
    print(book)  # 调用__str__方法
    book()       # 调用__call__方法

执行结果:

Python编程
Python编程 的作者是 Zhang San

十五、切片操作

Python 2中的切片方法

Python 2中使用__getslice__、__setslice__、__delslice__方法处理切片操作:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class MyCollection(object):

    def __getslice__(self, i, j):
        print('__getslice__被调用: i=%s, j=%s' % (i, j))

    def __setslice__(self, i, j, sequence):
        print('__setslice__被调用: i=%s, j=%s' % (i, j))

    def __delslice__(self, i, j):
        print('__delslice__被调用: i=%s, j=%s' % (i, j))


obj = MyCollection()
obj[-1:3]
obj[0:2] = [1, 2, 3]
del obj[0:3]

Python 3中的切片方法

Python 3统一使用__getitem__、__setitem__、__delitem__方法处理切片,通过slice对象传递参数:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class MyCollection(object):

    def __getitem__(self, index):
        if isinstance(index, slice):
            print("获取切片: start=%s, stop=%s, step=%s" %
                  (index.start, index.stop, index.step))

    def __setitem__(self, index, value):
        if isinstance(index, slice):
            print("设置切片: start=%s, stop=%s, step=%s" %
                  (index.start, index.stop, index.step))
            print("设置的值:", value)

    def __delitem__(self, index):
        if isinstance(index, slice):
            print("删除切片: start=%s, stop=%s, step=%s" %
                  (index.start, index.stop, index.step))


if __name__ == "__main__":
    obj = MyCollection()
    obj[-1:10]
    obj[-1:10:1] = [1, 2, 3, 4]
    del obj[-1:10:2]

执行结果:

获取切片: start=-1, stop=10, step=None
设置切片: start=-1, stop=10, step=1
设置的值: [1, 2, 3, 4]
删除切片: start=-1, stop=10, step=2

十六、算术运算符方法

__add__和__radd__

__add__:当类对象 + 其他对象时调用
__radd__:当其他对象 + 类对象时调用(左侧对象没有__add__方法时)

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Number:
    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        return self.value + other

    def __radd__(self, other):
        return other + self.value

    def __sub__(self, other):
        return self.value - other

    def __rsub__(self, other):
        return other - self.value


num = Number(100)
print(num + 50)    # 调用 __add__
print(50 + num)    # 调用 __radd__
print(num - 30)    # 调用 __sub__
print(30 - num)    # 调用 __rsub__

执行结果:

150
150
70
-70

__iadd__方法

__iadd__用于实现 += 运算符:

class Counter:
    def __init__(self, count=0):
        self.count = count

    def __iadd__(self, other):
        self.count += other
        return self

    def __str__(self):
        return str(self.count)


c = Counter(10)
c += 5
print(c)  # 输出 15

以上内容涵盖了Python中常用的内置方法(魔术方法),理解这些方法能够帮助开发者更好地设计和实现自定义类,实现更丰富的功能。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。