复式记账把所有账户归入五个根类别:资产、负债、权益、收入、费用。这个分类是三件事的依据:账户名合法性(解析器只接受以五个根名开头的名字)、余额正负号解释(同一负数在资产与收入账户里含义相反)、一条记录出现在资产负债表还是损益表。
本模块集中定义
AccountTypes、默认根名和分类谓词:一个五字段的具名元组存放五个根名,一组无状态函数在账户名字符串上做判定。五分类结构不止本模块一处——解析器的五个
name_*
选项(beancount/parser/options.py:322-330)及校验正则(beancount/parser/grammar.py:109-127)同样依赖它。模块不持有账本数据,也不校验账户根是否属于当前配置,只做根名提取、分类判断、部分参数类型断言,以及
is_root_account 的语法形状判断。
| 名称 | 位置 | 作用 |
|---|---|---|
| 模块 docstring | account_types.py:1-9 |
声称模块使用全局量与副作用;实际代码已无全局可变状态(见第 8 节) |
class AccountTypes(NamedTuple) |
:26-33 |
五个 str
字段:assets、liabilities、equity、income、expenses |
DEFAULT_ACCOUNT_TYPES |
:37-39 |
AccountTypes("Assets", "Liabilities", "Equity", "Income", "Expenses") |
get_account_type |
:42-55 |
取账户名第一段;带 Warning 注释说明不校验有效性 |
get_account_sort_key |
:58-69 |
排序键 (类型在元组里的下标, 账户全名) |
is_account_type |
:72-81 |
用正则判断"以某类型加分隔符开头" |
is_root_account |
:84-96 |
判断名字形状像不像一个根账户 |
is_balance_sheet_account |
:99-118 |
资产、负债、权益三类 |
is_income_statement_account |
:121-136 |
收入、费用两类 |
is_equity_account |
:139-153 |
仅权益 |
is_inverted_account |
:156-177 |
负债、收入、权益三类 |
get_account_sign |
:180-195 |
资产、费用返回 +1,其余返回 -1 |
AccountTypes
与默认值class AccountTypes(NamedTuple):
"""A tuple that contains the names of the root accounts."""
assets: str # the name of the prefix for the Asset subaccounts.
liabilities: str # the name of the prefix for the Liabilities subaccounts.
equity: str # the name of the prefix for the Equity subaccounts.
income: str # the name of the prefix for the Income subaccounts.
expenses: str # the name of the prefix for the Expenses subaccounts.
account_types.py:26-33。字段顺序(资产、负债、权益、收入、费用)决定
get_account_sort_key 所定义的类型排序——它直接拿
account_types.index(...)
当第一排序键(:69)。基线仓库仅测试并公开导出该函数(api.py:22,150),没有内部报表调用点。
DEFAULT_ACCOUNT_TYPES 在 :37-39
用五个英文名实例化。account_types_test.py:11-13 (test_basics)
只锁定它非 None 且 assets == "Assets"。
它是不可变具名元组而非全局可变状态:五个名字要么用默认值,要么由调用方从选项现装一个实例传进来。2024-12-22
commit 85950542 把它从 collections.namedtuple
改写成 typing.NamedTuple
类语法:字段类型注解取代了旧注释里的
a str,剩余描述文字移到行尾注释。
name_*
选项覆盖根名账本可以改这五个名字。beancount/parser/options.py:312-332
定义了对应的五个选项,默认值直接取自本模块:
_TYPES = account_types.DEFAULT_ACCOUNT_TYPES
...
Opt("name_assets", _TYPES.assets, converter=options_validate_root_account),
options.py:218,322。选项组的说明文字写明用途是自定义类别名,例如用
"Revenue" 代替 "Income"、用 "Capital" 代替
"Equity"(options.py:314-319)。options_validate_root_account(:121-133)要求值必须通过
account.is_valid_root,即
regex.fullmatch(ACC_COMP_TYPE_RE, value)(beancount/core/account.py:37,49-58),所以
"Foo:Bar" 这种带分隔符的值被拒绝,报
Invalid root account name(beancount/parser/options_test.py:67-74)。
反向装配在
options.py:744-763 (get_account_types):按固定顺序从选项字典取五个值构造
AccountTypes。需要类型判定的下游均调用
get_account_types
构造实例(summarize.py:205,224,317,387、check_drained.py:49、sellgains.py:95、export.py:146、doctor.py:431)。
names = map(
options.__getitem__,
("name_assets", "name_liabilities", "name_equity", "name_income", "name_expenses"),
)
return regex.compile(
"(?:{})(?:{}{})+".format("|".join(names), account.sep, account.ACC_COMP_NAME_RE)
)
beancount/parser/grammar.py:109-127 (valid_account_regexp)。解析器把五个根名拼成一个正则,每遇到账户名匹配一次,不中就记一条
Invalid account name
错误(grammar.py:286-290)。"账户属于五大类之一"这条约束由解析层强制,account_types.py
的任何函数都不做这项检查。
正则在选项被设置时重建(grammar.py:434-437),因此选项在账本文件里的位置有语义:options_test.py:87-97,110-132
锁定改名前写旧名合法、改名后写新名合法,而改名前写新名、改名后写旧名都报错。options_test.py:49-64
用一整套法语根名(Actif / Passif / Capital / Revenu / Dépenses)验证五个
open 全部解析成功。
get_account_type:取第一段,不问是否有效def get_account_type(account_name: Account) -> str:
"""Return the type of this account's name.
Warning: No check is made on the validity of the account type. This merely
returns the root account of the corresponding account name.
"""
assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
return account.split(account_name)[0]
account_types.py:42-55。实现是
account_name.split(":")[0](account.py:98-106)。Warning
注释是本模块最核心的边界声明:函数不知道当前配置有哪五个类型,也不接受
AccountTypes 参数。account_types_test.py:32
锁定
get_account_type("Invalid:Toys:Computer") == "Invalid"——不报错,照样返回。
这份宽松分三步定型,均在 2014-05-18:commit 720b9cdf
删掉函数里 assert atype in ACCOUNT_TYPES
的有效性断言,改为只返回第一段并补上 Warning 注释;同日
1c73039b 删掉最后的全局 ACCOUNT_TYPES 与
update_valid_account_names() 副作用函数;同日
e9289947 才把函数从 account_name_type
更名为现在的 get_account_type。
is_account_type:前缀匹配而非相等return bool(re.match("^{}{}".format(account_type, account.sep), account_name))
account_types.py:81。2018-01-29 commit
d83bb21a 加入,提交信息与
CHANGES:1180,1187-1188 都把它记为
get_account_type
之上的首选写法。区别在于它把分隔符也算进匹配:is_account_type("Assets", "AssetsUS:RBS:Checking")
为 False(account_types_test.py:68);先取
get_account_type 再比字符串同样得 False,写成
account_name.startswith("Assets") 则会误判。
代价是 account_type
未经转义直接拼进正则:传入含正则元字符的类型名会被当模式解释,例如
is_account_type("A.sets", "Assets:X") 返回
True。默认五个名字不含元字符,而选项值受
ACC_COMP_TYPE_RE
约束(只允许大写字母开头、字母数字和连字符),经选项验证的根名不会触发该问题。
is_root_account:形状判定,且规则比账户名规则窄return bool(account_name) and bool(re.match(r"([A-Z][A-Za-z0-9\-]+)$", account_name))
account_types.py:96。docstring 明说 "This function does
not verify whether the account root is a valid one, just that it is a
root account or
not."(:87-88)。account_types_test.py:70-85
的对照表锁定:五个默认根名为 True,任何带冒号的名字为
False,_invalid_ 为 False,而
Invalid 为 True——这条 True
断言在参数表和参数表之后重复出现一次。
这条正则与 account.py
里账户名组件的正则并不等价:ACC_COMP_TYPE_RE = r"[\p{Lu}][\p{L}\p{Nd}\-]*"(account.py:37)用
Unicode 属性且尾部是 *,这里是 ASCII 字符类且尾部是
+。后果有二:单字母根名 "A" 在
account.is_valid_root 下合法、在
is_root_account 下为
False;options_test.py:55 实际用过的合法配置值
"Dépenses" 同样为 False。
该函数在 v3 里没有调用点,api.py:21-28
的八个导出也不含它。现在的形态定型于 2020-11-15 commit
6baaf51f:此前签名带可选 account_types
参数,给了就用成员判定、不给才用正则,C++
移植时删除该参数只留正则分支;同日 86ee760f 把测试里
_invalid_ 的期望从 True 改成
False 并补上 Invalid → True。
get_account_signif account_types is None:
account_types = DEFAULT_ACCOUNT_TYPES
assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
account_type = get_account_type(account_name)
return +1 if account_type in (account_types.assets, account_types.expenses) else -1
account_types.py:191-195。资产与费用
+1,负债、权益、收入
-1。account_types_test.py:132-145 (test_get_account_sign)
的五行对照表逐类锁定这个映射。
这个符号对应"正常余额方向"的约定,不是解析器强制的规则:解析器原样保留
posting 符号,不按账户类型改写(grammar.py:461-475 原样构造
Amount,:948 原样放入
Posting;summarize_test.py:45-48,72-74
收录了合法的正数写法
Income:Salary 10000 USD)。按惯例收入记为负数,借贷平衡表现为一笔交易所有
posting 权重和为零。get_account_sign
把这套惯例方向换算成正向显示的乘数,但在当前基线仓库内部没有调用点(git grep get_account_sign
只命中
api.py、本模块和测试文件),doctor.py:457-464
只对汇总后的 net_income
整体取负打印,不逐账户调用该函数(见第 6 节)。
它是本模块唯一 account_types
参数可选的函数(:181),默认值自 2014-11-02 commit
a3a91792 引入时就在,提交信息给出的动机是给作者的
iracontribs 插件用。CHANGES:884-887 记
2018-04-29 SQL shell 新增多态
POSSIGN(_, account);95f7f3c6 的 diff
显示它落地为四个类型重载(Decimal、Amount、Position、Inventory),均调用
get_account_sign 决定取负——属于 v2 SQL
查询函数,与当前基线仓库内部报表无关。查询模块 2022-02-06 commit
3db1836a 整体移除后,get_account_sign
在仓库内部无调用点,只留在 api.py 公开面。
is_inverted_accountreturn account_type in (
account_types.liabilities,
account_types.income,
account_types.equity,
)
account_types.py:173-177。docstring
的定义是"符号与外部报表期望的相反,外部报表期望全是正号"(:159-160)。2021-01-31
commit 14808cfb 加入,提交正文原话为 "I'm starting to
invert some of my outputs for options
reporting."——作者开始反转其期权报告(options
reporting)中的部分输出。
它挑出的三类恰好就是 get_account_sign 返回
-1
的三类,两者对五大类的判断完全一致;account_types_test.py:117-130
与 test_get_account_sign
用的是同一组账户名。差别只在五大类之外:对
"Invalid:Foo",get_account_sign 走
else 分支返回
-1,is_inverted_account 的成员判定返回
False(详见第 8 节)。
它与 get_account_sign 一样,v3 内部零调用点,只经
api.py:28,164 导出。
is_balance_sheet_account(:99-118)覆盖资产、负债、权益;is_income_statement_account(:121-136)覆盖收入、费用;is_equity_account(:139-153)只比较权益一项。三者实现同构:两条
assert isinstance
检查账户名是字符串、account_types 是
AccountTypes 实例,再取 get_account_type
与成员比较。account_types_test.py:95-115 (test_is_account_categories)
用一张表同时验证前两个函数,第二个断言写成
not expected,把"非此即彼"也锁进了测试。
划分用于期末结转。beancount/ops/summarize.py
的三个函数——clear(:164-198)、clamp(:229-296)、cap(:334-373)——各自构造谓词
is_income_statement_account(account, account_types)(依次在
:191-193、:278-280、:363-365),交给
transfer_balances
把损益表账户的余额转到某个权益账户,使资产负债表配平。open(:44-108)不自行构造谓词,在
:103 调用 clear
完成同一件事。转入的目标账户名同样拼在权益根名下:options.py:766-785 (get_previous_accounts)
与 :788-802 (get_current_accounts) 用
account.join(equity, ...) 把
Opening-Balances、Earnings:Previous、Earnings:Current
等叶名接到 name_equity 之后。
另外两个消费者:check_drained.py:49-52 用
is_balance_sheet_account
限定"关闭时须清零"的检查范围;doctor.py:457-464
遍历实现树累加损益表账户余额,末行打印
"Net Income: {}".format(-net_income)——第 5.1
节所说约定的直接体现:内部累加原值(收入为负),对外打印整体取负。
排序键由 get_account_sort_key 给出:
return (account_types.index(get_account_type(account_name)), account_name)
account_types.py:69。第一键是类型在
AccountTypes
元组里的下标,第二键是账户全名。account_types_test.py:34-61
用 functools.partial
绑定类型元组后排序八个账户,期望顺序为资产、负债、权益、收入、费用,同类内按名字字母序。
这里曾有一个模块级字典 TYPES_ORDER,由
update_valid_account_names()
在导入时和每次解析前重设,2014-05-18 起改用元组自带的
.index()。线性查找与字典查找的差别可忽略,换来的是无全局状态。
| 决策 | 理由 | 证据 |
|---|---|---|
| 五个根名装进不可变具名元组,而非模块全局量 | 全局量意味着解析不同账本要靠副作用切换状态;元组按账本各持一份,函数保持纯粹 | account_types.py:26-39;e44f84e6、1c73039b(均
2014-05-18) |
字段顺序决定 get_account_sort_key 的类型排序 |
直接用 .index(),不需要另建顺序表;该函数仅测试覆盖并经
api.py 导出,无内部报表调用点 |
:69;account_types_test.py:34-61;git grep get_account_sort_key
仅命中 api.py/定义/测试 |
根名可由 name_* 选项覆盖 |
支持非英语账本,选项组说明给出 Revenue / Capital 的替换例子 | options.py:312-331,744-763;options_test.py:47-64 |
get_account_type、is_root_account
不校验类型是否在配置里 |
解析器负责账户合法性校验 | account_types.py:45-46,87-88;grammar.py:109-127,286-291 |
| 符号乘数按类型统一定义,而非逐账户配置 | 正常余额方向约定资产、费用以正表示,负债、权益、收入以负表示;get_account_sign
只提供这套约定到显示方向的换算乘数,不改写 posting 本身 |
account_types.py:195;account_types_test.py:132-145 |
| 内部一律存带符号原值 | 存原值才能让一笔交易的权重直接求和判平;get_account_sign
提供转正乘数,但基线仓库内部不调用它,doctor.py
只对汇总后的 net_income 整体取负 |
doctor.py:457-464;v2 曾提供显式
POSSIGN(CHANGES:884-887;95f7f3c6) |
get_account_sign 的 account_types
参数可选 |
提交信息给出的动机是给 iracontribs
插件用;参数从首次提交起即为可选,提交未进一步说明设计理由 |
account_types.py:181,191-192;a3a91792(2014-11-02) |
is_account_type 把分隔符纳入匹配 |
避免 startswith 把 AssetsUS:... 误判为
Assets 类 |
:81;account_types_test.py:68;CHANGES:1187-1188 |
划分函数用 assert 检查参数类型 |
提供提前且更针对性的类型失败;python -O
剥离断言后,字典等无同名属性的对象会在
.assets、.income 等属性访问处失败 |
:109-112,131-134,148-151,168-171 |
| 现象 | 后果 | 证据 |
|---|---|---|
get_account_type 对任何字符串都返回第一段 |
"Invalid:Foo" 返回 "Invalid"
而不报错,类型有效性全靠解析层 |
account_types.py:45-46,55;account_types_test.py:32 |
get_account_type("") 返回 "" |
"".split(":") 得 [""],空串走到
get_account_sign 会得到 -1 |
account.py:98-106;account_types.py:195 |
| 不带冒号的名字也能取到"类型" | get_account_type("Assets") 返回
"Assets",is_balance_sheet_account("Assets", ...)
为 True |
:55,113-118 |
get_account_sign 对未知类型返回 -1 |
五大类之外的名字被当作反向账户;没有"未知"这个返回值。省略第二参数时固定用英文默认根名,自定义根名账本若忘记传当前
AccountTypes(如
Actif:Cash)也会被当未知类型返回 -1 |
:191-195 |
is_balance_sheet_account、is_income_statement_account
对未知根名均返回 False |
测试里两者结果"互补"(not expected)只覆盖五个合法默认根名,未知字符串上两者同时为
False,不构成互补 |
:113-118,135-136;account_types_test.py:95-115 |
is_inverted_account 对未知类型返回
False |
与 get_account_sign 对同一个 "Invalid:Foo"
给出相反结论(-1 对 False) |
:173-177,195 |
is_account_type 不转义
account_type,也不做 isinstance 断言 |
类型名里的正则元字符按模式解释,is_account_type("A.sets", "Assets:X")
为
True;且只检查"类型名加冒号"前缀,不校验冒号后的账户组件,is_account_type("Assets", "Assets:")
同样为 True |
:72-81 |
is_root_account 的正则要求至少两个字符 |
单字母根名 "A" 返回 False,而
account.is_valid_root("A") 为 True |
:96;account.py:37,58 |
is_root_account 只认 ASCII 字母,且 $
可在末尾换行符前匹配 |
"Dépenses" 是合法的 name_expenses
取值却判为非根账户;"Assets\n" 因 re.match 的
$ 语义返回 True |
:96;options_test.py:55 |
is_root_account 在 v3 无调用点,也未导出 |
只有测试引用它,api.py 的八个导出里没有它 |
api.py:21-28 |
get_account_sign、is_inverted_account、is_equity_account
在 v3 内部无调用点 |
三者只经 api.py 对外提供;get_account_sign
的最后一个内部消费者随查询模块于 2022-02-06 移除 |
api.py:21,26,28;3db1836a |
get_account_sort_key 对未知类型抛异常,且不校验
account_types 类型 |
tuple.index 找不到成员时抛
ValueError,没有兜底下标;与 get_account_sign
一样不做 isinstance(account_types, AccountTypes)
断言,四个分类谓词则会断言 |
:58-69,99-195 |
AccountTypes 的 str
注解不做运行期校验,也不保证五个根名互异 |
直接构造可放入非字符串或重复根名;重复值会让
tuple.index()
总取第一次出现的位置,可能使分类集合意外重叠 |
:26-39,69 |
划分函数用 assert 做类型检查 |
python -O 下断言被剥离,传入非
AccountTypes 的对象会在属性访问处才失败 |
:109-112,131-134,148-151,168-171 |
| 【文档漂移】模块 docstring 说使用 globals 与 side-effects | 全局量与 update_valid_account_names() 已于 2014-05-18
删除,模块现在只有常量;2025-12-25 commit 01adfb37 把
glboals→globals、side-effect→side-effects、Maybe we change→Maybe we will change,未纠正全局状态已不存在这一过时描述 |
:1-9;1c73039b;01adfb37 |
【文档漂移】get_account_sort_key 的 docstring
缺参数(历史) |
account_name 一项到 2026-01-01 commit
448580ff 才补进 Args |
:61-68;448580ff |
account_types_test.py 共 8 个测试,一个类
TestAccountTypes(:10):
| 测试 | 行号 | 锁定的行为 |
|---|---|---|
test_basics |
11-13 | DEFAULT_ACCOUNT_TYPES 存在且
assets == "Assets" |
test_get_account_type |
15-32 | 五类账户各取到正确根名;"Invalid:Toys:Computer" 返回
"Invalid" 而不报错 |
test_get_account_sort_key |
34-61 | 八个账户排序为资产、负债、权益、收入、费用,同类内按名字升序 |
test_is_account_type |
63-68 | 类型匹配、类型不匹配、缺分隔符("AssetsUS:RBS:Checking")三种情形 |
test_is_root_account |
70-85 | 十个名字的形状判定;Invalid 为
True、_invalid_ 为 False |
test_is_account_categories |
95-115 | 五类账户的资产负债表 / 损益表归属,两个函数结果互补 |
test_is_inverted_account |
117-130 | 五类账户的反号归属:负债、权益、收入为 True |
test_get_account_sign |
132-145 | 五类账户的符号:资产 +1、负债 -1、权益
-1、收入 -1、费用 +1 |
测试文件里还有一个类属性
OPTIONS(:87-93),字面量列出五个
name_*
选项及默认值,无任何测试引用它。自定义根名的端到端行为由
beancount/parser/options_test.py:47-132 (TestAccountTypeOptions)
覆盖。
没有测试覆盖的行为:is_equity_account
完全无测试;所有函数的 assert
分支;get_account_sort_key 遇未知类型抛
ValueError;get_account_sign
省略第二参数走默认值的路径(测试总是显式传
DEFAULT_ACCOUNT_TYPES);用非默认 AccountTypes
实例调用判定函数;空字符串账户名;is_account_type
的正则元字符注入与空叶名(如
"Assets:");未知类型在两个报表谓词、is_inverted_account、get_account_sign
上的结果差异;is_root_account
的单字母、Unicode、末尾换行行为;AccountTypes
字段重复或非字符串的情形。
| 日期 | 提交 / 记录 | 变化 |
|---|---|---|
| 2014-02-08 | 4d213024 |
创建 account_types.py、AccountTypes
及现行模块 docstring 的初版(当时路径为
src/python/beancount/core/) |
| 2014-05-03 | 911fdd76 |
把账户类型相关函数从 account.py 移入
account_types.py,使 account.py 不再依赖
account_types;迁移后的 account_types.py
反而依赖 account.py 的分隔符等基础能力 |
| 2014-05-18 | e44f84e6、720b9cdf |
删除模块级 TYPES_ORDER 字典,排序键改用
account_types.index(...);随后删除
account_name_type() 里
assert atype in ACCOUNT_TYPES
的有效性断言,改为只返回第一段并加 Warning 注释 |
| 2014-05-18 | 59a92b67、1c73039b、e9289947 |
三个分类谓词的第二参数从 options 字典改为显式
AccountTypes 实例;删除全局 ACCOUNT_TYPES 与
update_valid_account_names()
副作用;account_name_type 更名为
get_account_type |
| 2014-07-05 | c291509f |
账户名语法校验函数从 account_types.py(原
is_valid_account_name)移到 account.py(现
is_valid),用于把
parser.documents.walk_accounts() 上移到 core 层 |
| 2014-11-02 | a3a91792 |
新增 get_account_sign(),account_types
参数即刻设为可选 |
| 2014-12-06 | 8c1b9d28 |
排序接口从返回闭包的 get_account_sort_function
重构为直接返回排序键的 get_account_sort_key;查询层新增
ACCOUNT_SORTKEY,使查询余额输出按账户类型排序 |
| 2017-04-30 | 859f341e |
仓库布局从 src/python/beancount/... 迁到
beancount/...;此前提交引用的路径都带旧前缀 |
| 2018-01-29 | d83bb21a、CHANGES:1187-1188 |
新增 is_account_type(),CHANGES 记为
get_account_type() 之上的首选写法 |
| 2018-04-29 | 95f7f3c6、CHANGES:884-887 |
CHANGES 记 SQL shell 新增多态
POSSIGN(_, account);query_env.py 的 diff
显示它落地为四个类型重载,均调用 get_account_sign |
| 2020-11-15 | 49a8b25c、ae1d102c、8cd2d031、d590b26f、8422c90e |
逐个函数移植到 C++ 扩展;c312f227 同日补类型注解 |
| 2020-11-15 | 6baaf51f、86ee760f |
is_root_account 删除 account_types
参数只留正则;测试里 _invalid_ 期望改为
False,补 Invalid → True |
| 2021-01-31 | 14808cfb |
新增
is_inverted_account,提交正文称作者开始反转其期权报告(options
reporting)中的部分输出 |
| 2022-02-06 | 3db1836a |
移除查询模块,get_account_sign
失去最后一个内部调用点 |
| 2022-07-24 | b5d2b15e |
公开 API 汇总到 api.py,当时导出本模块 7 个函数(不含
get_account_sort_key) |
| 2024-06-16 | 27c78c8b |
移除 C++ 代码与 Bazel 构建,回到纯 Python 实现 |
| 2024-06-30 | 5539c79b |
补入遗漏的 get_account_sort_key,api.py
导出的本模块函数增至现行的 8 个 |
| 2024-12-22 | 85950542 |
AccountTypes 从 collections.namedtuple
改为 typing.NamedTuple 类语法 |
| 2024-12-22 | 5871f962 |
测试里删除
try: from beancount.core import account_types / except ImportError: from beancount.ccore import _core
的双路径导入 |
| 2025-12-25 | 01adfb37 |
修订 docstring 拼写;同时把 is_account_type 那段误抄自
get_account_type 的说明改写为正确描述 |
| 2026-01-01 | 448580ff |
按 Google 风格补全 Args/Returns,get_account_sort_key
补上 account_name 一项 |
beancount/core/account.py
的
sep(:29)、split(:98-108)与类型别名
Account = str(:25,在
TYPE_CHECKING
块里导入,account_types.py:22-23)。account.py
不反向依赖本模块,无循环导入。beancount/parser/options.py:218
拿 DEFAULT_ACCOUNT_TYPES
当五个选项的默认值,:744-763 (get_account_types)
反向把选项装配回
AccountTypes——运行期取得当前账本类型元组的唯一入口。beancount/parser/grammar.py:109-127
用五个根名拼账户名正则,:286-291
逐个账户名校验,:434-437 在选项变化时重建正则。beancount/ops/summarize.py:28,191-193,278-280,363-365
用 is_income_statement_account
圈定要转入权益的账户;目标账户名由
options.py:766-785,797-802 在权益根名下拼出。plugins/check_drained.py:49-52(资产负债表账户才检查清零)、plugins/sellgains.py:95-97,125-127(用
get_account_type
排除收入腿)、projects/export.py:146-151(只导出资产与负债)、scripts/doctor.py:431,457-464(累加损益表账户并取负打印净收入)。AccountTypes
作为可迭代五元组还可直接充当 realization.realize() 的
min_accounts
参数,确保空账本也建出五个根节点(core/realization.py:250,269-273;core/realization_test.py:273-278)。beancount/api.py:21-28
导入八个函数、:149-164 列入 __all__,另有
:80,152 转出
options.get_account_types。is_root_account
不在其中。beancount/core/account_types.py:1-9 模块
docstring;11-23 导入与 TYPE_CHECKING;26-33
AccountTypes;37-39
DEFAULT_ACCOUNT_TYPES;42-55
get_account_type(45-46 Warning);58-69
get_account_sort_key;72-81
is_account_type;84-96 is_root_account(87-88
不校验有效性的声明);99-118
is_balance_sheet_account;121-136
is_income_statement_account;139-153
is_equity_account;156-177
is_inverted_account(159-160 反号定义);180-195
get_account_sign。
beancount/core/account_types_test.py:11-13、15-32、34-61、63-68、70-85、87-93(未被引用的
OPTIONS)、95-115、117-130、132-145。
其它:beancount/core/account.py:25,29,37,41,49-58,98-108;beancount/core/realization.py:211,250,269-273;beancount/core/realization_test.py:273-278;beancount/parser/options.py:121-133,218,312-332,744-763,766-785,788-802;beancount/parser/options_test.py:47-132;beancount/parser/grammar.py:109-127,286-290,434-437;beancount/ops/summarize.py:28,44-108,164-198,191-193,229-296,278-280,334-373,363-365;beancount/plugins/check_drained.py:49-52;beancount/plugins/sellgains.py:95-97,125-127;beancount/projects/export.py:146-151;beancount/scripts/doctor.py:431,457-464;beancount/api.py:21-28,80,149-164;CHANGES:884-887,1180,1187-1188。
commit:4d213024(2014-02-08)、911fdd76(2014-05-03)、e44f84e6/720b9cdf/59a92b67/1c73039b/e9289947(均
2014-05-18)、c291509f(2014-07-05)、a3a91792(2014-11-02)、8c1b9d28(2014-12-06)、859f341e(2017-04-30)、d83bb21a(2018-01-29)、95f7f3c6(2018-04-29)、49a8b25c/ae1d102c/8cd2d031/d590b26f/8422c90e/6baaf51f/86ee760f/c312f227(均
2020-11-15)、14808cfb(2021-01-31)、3db1836a(2022-02-06)、b5d2b15e(2022-07-24)、27c78c8b(2024-06-16)、5539c79b(2024-06-30)、85950542(2024-12-22)、5871f962(2024-12-22)、129e090e(2025-03-17)、01adfb37(2025-12-25)、448580ff(2026-01-01)。