每周一个 Python 模块 | os.path

本文深入探讨了Python的os.path模块,讲解了如何解析、构建和规范化路径,以及如何测试文件属性和时间。通过实例展示了split(), basename(), dirname(), splitext(), commonprefix(), join(), expanduser(), normpath(), abspath()等函数的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

专栏地址:每周一个 Python 模块

本文基于 Python3 编写测试。

os.path 模块是跨平台的,即使不打算在平台之间移植自己的程序也应该用 os.path,好处多多。

解析路径

第一组 os.path 函数可用于将表示文件名的字符串解析为其组成部分。重要的是要意识到这些功能不依赖于实际存在的路径。

路径解析取决于以下定义的一些 os 变量:

  • os.sep- 路径部分之间的分隔符(例如,“ /”或“ \”)。
  • os.extsep- 文件名和文件“扩展名”之间的分隔符(例如,“ .”)。
  • os.pardir- 路径组件,意味着将目录树向上遍历一级(例如,“ ..”)。
  • os.curdir- 引用当前目录的路径组件(例如,“ .”)。

split() 函数将路径分成两个独立的部分,并返回一个tuple结果。第二个元素是路径的最后一个元素,第一个元素是它之前的所有元素。

import os.path

PATHS = [
    '/one/two/three',
    '/one/two/three/',
    '/',
    '.',
    '',
]

for path in PATHS:
    print('{!r:>17} : {}'.format(path, os.path.split(path)))
    
# output
# '/one/two/three' : ('/one/two', 'three')
# '/one/two/three/' : ('/one/two/three', '')
#               '/' : ('/', '')
#               '.' : ('', '.')
#                '' : ('', '')
复制代码

当输入参数以 os.sep 结束时,路径的最后一个元素是一个空字符串。

basename()函数返回一个等于 split() 返回值的第二部分的值。

import os.path

PATHS = [
    '/one/two/three',
    '/one/two/three/',
    '/',
    '.',
    '',
]

for path in PATHS:
    print('{!r:>17} : {!r}'.format(path, os.path.basename(path)))
    
# output
# '/one/two/three' : 'three'
# '/one/two/three/' : ''
#               '/' : ''
#               '.' : '.'
#                '' : ''
复制代码

完整路径被剥离到最后一个元素,无论是指文件还是目录。

dirname()函数返回拆分路径的第一部分:

import os.path

PATHS = [
    '/one/two/three',
    '/one/two/three/',
    '/',
    '.',
    '',
]

for path in PATHS:
    print('{!r:>17} : {!r}'.format(path, os.path.dirname(path)))
    
# output
# '/one/two/three' : '/one/two'
# '/one/two/three/' : '/one/two/three'
#               '/' : '/'
#               '.' : ''
#                '' : ''
复制代码

结合basename()dirname() 的结果可以返回原始路径。

splitext()类似于split(),但在扩展分隔符上划分路径,而不是目录分隔符。

import os.path

PATHS = [
    'filename.txt',
    'filename',
    '/path/to/filename.txt',
    '/',
    '',
    'my-archive.tar.gz',
    'no-extension.',
]

for path in PATHS:
    print('{!r:>21} : {!r}'.format(path, os.path.splitext(path)))
    
# output
#        'filename.txt' : ('filename', '.txt')
#            'filename' : ('filename', '')
# '/path/to/filename.txt' : ('/path/to/filename', '.txt')
#                   '/' : ('/', '')
#                    '' : ('', '')
#   'my-archive.tar.gz' : ('my-archive.tar', '.gz')
#       'no-extension.' : ('no-extension', '.')
复制代码

os.extsep在查找扩展名时仅匹配最后一次出现的分隔符,因此如果文件名具有多个扩展名,则会按照最后一个扩展名进行拆分。

commonprefix()将路径列表作为参数,并返回表示所有路径中存在的公共前缀的单个字符串。该值还可以表示实际上不存在的路径,并且路径分隔符不包括在考虑中。

import os.path

paths = ['/one/two/three/four',
         '/one/two/threefold',
         '/one/two/three/',
         ]
for path in paths:
    print('PATH:', path)

print()
print('PREFIX:', os.path.commonprefix(paths))

# output
# PATH: /one/two/three/four
# PATH: /one/two/threefold
# PATH: /one/two/three/
# 
# PREFIX: /one/two/three
复制代码

在此示例中,公共前缀字符串是/one/two/three,即使一个路径不包含名为的目录three

commonpath() 考虑路径分隔符,并返回不包含部分路径值的前缀。

import os.path

paths = ['/one/two/three/four',
         '/one/two/threefold',
         '/one/two/three/',
         ]
for path in paths:
    print('PATH:', path)

print()
print('PREFIX:', os.path.commonpath(paths))

# output
# PATH: /one/two/three/four
# PATH: /one/two/threefold
# PATH: /one/two/three/
# 
# PREFIX: /one/two
复制代码

构建路径

除了将现有路径分开之外,经常需要从其他字符串构建路径。要将多个路径组合为单个值,可以使用join()

import os.path

PATHS = [
    ('one', 'two', 'three'),
    ('/', 'one', 'two', 'three'),
    ('/one', '/two', '/three'),
]

for parts in PATHS:
    print('{} : {!r}'.format(parts, os.path.join(*parts)))
    
# output
# ('one', 'two', 'three') : 'one/two/three'
# ('/', 'one', 'two', 'three') : '/one/two/three'
# ('/one', '/two', '/three') : '/three'
复制代码

如果有任何一个参数是以 os.sep 开头的,则先前所有的参数都会被丢弃,并将该值作为返回值的开头。

也可以使用包含可以自动扩展的“可变”组件的路径。例如,expanduser()~ 字符转换为用户主目录的名称。

import os.path

for user in ['', 'dhellmann', 'nosuchuser']:
    lookup = '~' + user
    print('{!r:>15} : {!r}'.format(lookup, os.path.expanduser(lookup)))
    
# output
#             '~' : '/Users/dhellmann'
#    '~dhellmann' : '/Users/dhellmann'
#   '~nosuchuser' : '~nosuchuser'
复制代码

如果找不到用户的主目录,则返回字符串不变,如~nosuchuser

expandvars() 更通用,扩展路径中存在的任何 shell 环境变量。

import os.path
import os

os.environ['MYVAR'] = 'VALUE'

print(os.path.expandvars('/path/to/$MYVAR'))	# /path/to/VALUE
复制代码

并不会验证文件或路径是否存在。

规范化路径

使用join() 组合的路径可能会有额外的分隔符或相对路径。用 normpath()来清理它们:

import os.path

PATHS = [
    'one//two//three',
    'one/./two/./three',
    'one/../alt/two/three',
]

for path in PATHS:
    print('{!r:>22} : {!r}'.format(path, os.path.normpath(path)))
    
# output
#      'one//two//three' : 'one/two/three'
#    'one/./two/./three' : 'one/two/three'
# 'one/../alt/two/three' : 'alt/two/three'
复制代码

要将相对路径转换为绝对文件名,请使用 abspath()

import os
import os.path

os.chdir('/usr')

PATHS = [
    '.',
    '..',
    './one/two/three',
    '../one/two/three',
]

for path in PATHS:
    print('{!r:>21} : {!r}'.format(path, os.path.abspath(path)))
    
# output
#                   '.' : '/usr'
#                  '..' : '/'
#     './one/two/three' : '/usr/one/two/three'
#    '../one/two/three' : '/one/two/three'
复制代码

文件时间

除了使用路径之外,os.path还包括用于检索文件属性的函数,类似于 os.stat()

import os.path
import time

print('File         :', __file__)
print('Access time  :', time.ctime(os.path.getatime(__file__)))
print('Modified time:', time.ctime(os.path.getmtime(__file__)))
print('Change time  :', time.ctime(os.path.getctime(__file__)))
print('Size         :', os.path.getsize(__file__))

# output
# File         : ospath_properties.py
# Access time  : Sun Mar 18 16:21:22 2018
# Modified time: Fri Nov 11 17:18:44 2016
# Change time  : Fri Nov 11 17:18:44 2016
# Size         : 481
复制代码

os.path.getatime()返回访问时间, os.path.getmtime()返回修改时间,os.path.getctime()返回创建时间。 os.path.getsize()返回文件中的数据量,以字节为单位表示。

测试文件

当程序遇到路径名时,通常需要知道路径是指文件,目录还是符号链接以及它是否存在。 os.path包括测试所有这些条件的功能。

import os.path

FILENAMES = [
    __file__,
    os.path.dirname(__file__),
    '/',
    './broken_link',
]

for file in FILENAMES:
    print('File        : {!r}'.format(file))
    print('Absolute    :', os.path.isabs(file))
    print('Is File?    :', os.path.isfile(file))
    print('Is Dir?     :', os.path.isdir(file))
    print('Is Link?    :', os.path.islink(file))
    print('Mountpoint? :', os.path.ismount(file))
    print('Exists?     :', os.path.exists(file))
    print('Link Exists?:', os.path.lexists(file))
    print()
    
# output
# File        : 'ospath_tests.py'
# Absolute    : False
# Is File?    : True
# Is Dir?     : False
# Is Link?    : False
# Mountpoint? : False
# Exists?     : True
# Link Exists?: True
# 
# File        : ''
# Absolute    : False
# Is File?    : False
# Is Dir?     : False
# Is Link?    : False
# Mountpoint? : False
# Exists?     : False
# Link Exists?: False
# 
# File        : '/'
# Absolute    : True
# Is File?    : False
# Is Dir?     : True
# Is Link?    : False
# Mountpoint? : True
# Exists?     : True
# Link Exists?: True
# 
# File        : './broken_link'
# Absolute    : False
# Is File?    : False
# Is Dir?     : False
# Is Link?    : True
# Mountpoint? : False
# Exists?     : False
# Link Exists?: True
复制代码

所有测试函数都返回布尔值。

相关文档:

pymotw.com/3/os.path/i…

<think>好的,我需要帮助用户开发一个微信机器人来执行每周定时任务。根据用户提供的引用内容,他们已经有一些使用企业微信群聊机器人和Python脚本的例子。用户现在想扩展到每周定时任务,所以我要先回顾现有的方法,再调整到每周的频率。 首先,用户之前可能用过curl命令和Python脚本通过企业微信的API发送消息。引用1中的例子是使用shell脚本结合crontab来定时推送,而引用2是用Pythonos.system调用curl,并且用了循环和延迟。但每周任务需要不同的crontab设置,可能需要检查现有的代码如何调整。接下来,我需要考虑如何实现每周定时。通常,Linux的crontab可以设置每周执行,例如018 **1,3,5表示每周一、三、五18点执行。但用户现在需要的是每周任务,比如每周一的某个时间。所以需要指导用户修改crontab的时间表达式。另外,用户可能需要更稳定的方法,比如使用Python的内置调度库,如apscheduler,这样可能比依赖crontab更可控,尤其是在跨平台的情况下。但也要考虑用户的技术背景,如果用户熟悉crontab,可能更倾向于使用cron任务。 然后,需要确保代码的正确性。在引用2中,用户使用了一个循环,但如果是每周执行一次,循环可能不需要,或者需要调整循环间隔。例如,使用time.sleep(604800)来等待一周,但这样可能不够可靠,因为脚本可能会中断。因此,更推荐使用crontab来触发每周执行。 还要考虑消息内容的动态生成,比如日报中的日期和项目信息是否需要自动更新。可能需要用Python的datetime模块来生成当前日期,并格式化到消息内容中。安全性方面,提醒用户保护好API密钥,不要泄露在代码或版本控制中。可能建议使用环境变量来存储密钥。最后,生成相关问题,帮助用户深入理解,比如如何测试机器人、如何处理多个任务、如何监控执行情况等。</think>### 微信机器人实现每周定时任务的方法 #### 一、核心实现步骤 1. **API接口准备** 企业微信机器人通过Webhook地址发送消息,格式为: $$https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的密钥$$ 需在企业微信客户端创建群机器人获取密钥[^1]。 2. **Python脚本编写** ```python import requests import datetime def send_weekly_report(): webhook_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=你的密钥" today = datetime.datetime.now().strftime("%Y年%m月%d日") payload = { "msgtype": "text", "text": { "content": f"{today} 周报\n1. 本周工作总结\n2. 下周计划\n3. 风险预警", "mentioned_list": ["@all"] } } requests.post(webhook_url, json=payload) ``` 3. **定时任务配置** - **Linux服务器方案** 使用crontab设置每周一9:00执行: ```bash 0 9 * * 1 python3 /path/to/your_script.py ``` - **纯Python方案** 使用`apscheduler`库实现跨平台定时: ```python from apscheduler.schedulers.blocking import BlockingScheduler scheduler = BlockingScheduler() scheduler.add_job(send_weekly_report, &#39;cron&#39;, day_of_week=&#39;mon&#39;, hour=9) scheduler.start() ``` #### 二、关键注意事项 1. **消息模板优化** - 使用Markdown格式增强可读性: ```json "msgtype": "markdown", "markdown": { "content": "**本周重点项目**\n> • 项目A进度80%\n> • 项目B延期风险!" } ``` 2. **错误处理机制** ```python try: response = requests.post(webhook_url, json=payload, timeout=5) if response.json()[&#39;errcode&#39;] != 0: print(f"发送失败: {response.text}") except Exception as e: print(f"连接异常: {str(e)}") ``` 3. **安全建议** - 将API密钥存储在环境变量中 - 设置IP白名单限制访问 - 启用企业微信消息加密功能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值