python-descriptors-mro
Skill0 starsChanged 39 days agoMITView on GitHub
Use when designing Python attribute protocols, multiple inheritance, or metaclasses — descriptor precedence, __set_name__, __slots__ interaction, C3 linearization rules, super() order, "MRO conflict" TypeError; applies when building validators, ORM fields, property-like wrappers, or debugging surprising attribute lookups
In this repository66 other files it gives its agents.
- AGENTS.mdAGENTS.md
- postgres-locking-joinsSkill
- ai-bug-patternsSkill
- compressed-ndjson-boundariesSkill
- http-resume-integritySkill
- linux-io-latency-triageSkill
- macos-disk-space-recoverySkill
- minimal-sufficient-evidenceSkill
- modularize-large-filesSkill
- patch-reproducer-validitySkill
- prompt-cache-boundariesSkill
- proton-drive-selective-backupSkill
- transactional-outbox-deliverySkill
- conventional-commitsSkill
- git-advanced-mergingSkill
- git-bisect-forensicsSkill
- git-data-recoverySkill
- git-hooksSkill
- git-rerereSkill
- git-reset-mechanicsSkill
- git-revisions-syntaxSkill
- git-rewriting-historySkill
- git-submodulesSkill
- git-worktreesSkill
- github-ssh-keysSkill
- npm-publish-ci-pitfallsSkill
- sapling-stacked-pr-workflowSkill
- go-concurrency-patternsSkill
- go-data-idiomsSkill
- go-error-handlingSkill
- go-interfaces-embeddingSkill
- go-pprof-profilingSkill
- marketing-funnel-diagnosisSkill
- marketing-geo-experimentsSkill
- marketing-incrementalitySkill
- marketing-positioning-testsSkill
- python-logging-cookbookSkill
- python-scaling-regression-testsSkill
- python-unicode-gotchasSkill
- rust-compile-time-invariantsSkill
- rust-deterministic-concurrency-testsSkill
- rust-error-identity-boundariesSkill
- rust-regex-search-contractsSkill
- rust-runtime-bug-classesSkill
- rust-tokio-actor-deliverySkill
- rust-tokio-cancellation-safetySkill
- sales-discovery-qualificationSkill
- sales-mutual-action-plansSkill
- sales-pipeline-forecast-calibrationSkill
- sales-value-negotiationSkill
- ai-triage-evaluationSkill
- container-image-patchingSkill
- dependency-artifact-integritySkill
- dnssec-sentinel-diagnosticsSkill
- iam-policy-change-replaySkill
- rbvm-applicabilitySkill
- rbvm-asset-evidenceSkill
- rbvm-guarded-remediationSkill
- rbvm-priority-decisionsSkill
- rbvm-risk-exceptionsSkill
- The first 60 shown.
The file
Files
Python Descriptors & MRO
Attribute access walks type(obj).__mro__ via __getattribute__. Data descriptors win over instance __dict__; non-data descriptors lose to it. super() follows the MRO of type(self), not the syntactic parent.
Attribute lookup order
| # | Source | Condition |
| 1 | Data descriptor from MRO | defines __set__ or __delete__ |
| 2 | obj.__dict__[name] | instance variable |
| 3 | Non-data descriptor / class var | defines only __get__ |
| 4 | __getattr__ | steps 1–3 all miss |
vars(cls)[name] returns the descriptor object itself — bypasses the protocol.
Descriptor protocol
class D:
def __set_name__(self, owner, name): # fires once at class creation
self.private = f'_{name}'
def __get__(self, obj, objtype=None):
if obj is None: return self # access via class
return getattr(obj, self.private)
def __set__(self, obj, value): # presence → DATA descriptor
setattr(obj, self.private, value)Descriptors must live on the class. Assigning after definition (setattr(cls, 'x', D())) skips __set_name__ — call it manually.
Functions as descriptors
| Wrapper | __get__ returns |
| plain function | MethodType(f, obj) |
@classmethod | MethodType(f, cls) |
@staticmethod | the raw function |
@property | result of fget(obj) |
__slots__
Each slot is a data descriptor into a fixed C array. ~35% faster attribute access, ~3× less memory. Incompatible with functools.cached_property. A subclass without __slots__ re-adds __dict__, erasing the saving.
C3 linearization
L[C(B1..Bn)] = C + merge(L[B1], …, L[Bn], [B1, …, Bn])
Merge rule: take the head of the first list whose head does not appear in the tail of any other list; remove from all; repeat. If none qualifies, raise TypeError: MRO conflict.
class A(X, Y): ... # L[A] forces X before Y
class B(Y, X): ... # L[B] forces Y before X
class C(A, B): ... # TypeError — irreconcilablePitfalls
- Non-data descriptor shadowed by instance attr:
obj.m = 5silently overrides a method-like descriptor. Define__set__(raise, or accept) to stop it. __set_name__never fires for post-hoc assignment:setattr(cls, 'x', D())— callD().__set_name__(cls, 'x')yourself.vars()/obj.__dict__bypasses descriptors: useful for introspection, dangerous for writes.super()bare form requires a class cell: fails in nested functions or when copied to a class without__class__closure.- "Diamond" inheritance order matters: list the more specific parent first;
class G(F, E)fails ifEextendsF. - Redundant bases break C3:
class B(A, O)whenAalready inherits fromO— raisesTypeError.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

