The Story That Ties These Three Ideas Together ☕इन तीन विचारों को जोड़ने वाली कहानी ☕把三个概念串起来的故事 ☕
On the wall: posted rules — STANDARD_CUP = 250 ml, MAX_BREW_TEMP = 95°C, TAX_RATE = 10%. The same in every branch. Nobody edits them. These are static variables.
Behind the counter: a thermometer, a scale, a stopwatch, a calculator. Anyone can grab one. They do not care whose drink is being made. Pure tools. These are static methods.
At the espresso machine: three signature drinks — Espresso, Latte, Cappuccino. Every barista knows a general
prepare() step, but each drink is prepared completely differently. For a Latte, "prepare" does not mean "grind and extract for 25 seconds" — it means "steam milk to 65°C and pour". Same call, different result. That is method overriding.Wire all three together and you get a family of classes that shares what should be shared and customises what should be customised.
दीवार पर: लगे हुए नियम — STANDARD_CUP = 250 ml, MAX_BREW_TEMP = 95°C, TAX_RATE = 10%। हर branch में एक जैसे। कोई इन्हें नहीं बदलता। ये static variables हैं।
Counter के पीछे: thermometer, तराज़ू, stopwatch, calculator। कोई भी उठा सकता है। उन्हें फ़र्क़ नहीं पड़ता कि drink किसका बन रहा है। शुद्ध औज़ार। ये static methods हैं।
Espresso machine पर: तीन ख़ास drinks — Espresso, Latte, Cappuccino। हर barista एक सामान्य
prepare() step जानता है, पर हर drink बिल्कुल अलग तरह से बनता है। Latte के लिए "prepare" का मतलब "पीसो और 25 seconds extract करो" नहीं — इसका मतलब है "दूध को 65°C तक भाप दो और डालो"। एक ही call, अलग नतीजा। यही method overriding है।तीनों को जोड़ दें तो classes का एक ऐसा परिवार मिलता है जो साझा चीज़ें साझा करता है और अलग चीज़ें अपने हिसाब से बदलता है।
墙上:张贴的规则 — STANDARD_CUP = 250 ml,MAX_BREW_TEMP = 95°C,TAX_RATE = 10%。每家分店都一样,没人修改。这些是 静态变量。
柜台后面:温度计、秤、秒表、计算器。谁都可以拿来用,它们不关心在做谁的饮品。纯粹的工具。这些是 静态方法。
咖啡机前:三款招牌饮品 — 浓缩咖啡、拿铁、卡布奇诺。每位咖啡师都知道一个通用的
prepare() 步骤,但每款饮品的做法 完全不同。对拿铁来说,"prepare"不是"研磨并萃取 25 秒",而是"把牛奶蒸到 65°C 再倒入"。同样的调用,不同的结果。这就是 方法重写。把三者结合起来,你就得到一个类家族:该共享的 共享,该定制的 定制。
Static variables = one copy of a constant, shared by every instance. Static methods = plain functions that live inside the class. Method overriding = a child class redefining a parent's method to change its behaviour. Together they turn one rigid class into a flexible family of classes.
Static variables = एक constant की एक copy, हर instance साझा करता है। Static methods = class के अंदर रहने वाले सादे functions। Method overriding = child class parent के method को दोबारा define करके उसका व्यवहार बदलती है। तीनों मिलकर एक सख़्त class को classes के लचीले परिवार में बदल देते हैं।
静态变量 = 一个常量只有一份,所有实例共享。静态方法 = 住在类里面的普通函数。方法重写 = 子类重新定义父类的方法来改变其行为。三者结合,把一个死板的类变成灵活的类家族。
The Python documentation calls these class variables (or class attributes). "Static variable" is the name used in languages such as Java and C++. Both names mean the same thing here: a value defined directly in the class body. Python does not stop anyone from changing them — UPPER_SNAKE_CASE is only a signal to other programmers.
Python documentation इन्हें class variables (या class attributes) कहती है। "Static variable" Java और C++ जैसी languages का नाम है। यहाँ दोनों नामों का एक ही मतलब है: class body में सीधे लिखी value। Python इन्हें बदलने से किसी को नहीं रोकता — UPPER_SNAKE_CASE सिर्फ़ दूसरे programmers के लिए एक संकेत है।
Python 官方文档把它们称为 类变量(或类属性)。"静态变量"是 Java、C++ 等语言的叫法。在这里两个名字指同一件事:直接写在类体中的值。Python 并不阻止任何人修改它们 — UPPER_SNAKE_CASE 只是给其他程序员的一个信号。
Look for the interactive boxes: the Shadow Lab (Section 03), the Static Method Machine (04), One Call, Many Drinks (05), Replace vs Extend (06) and the Bug Doctor (09). Every result comes from real Python runs.
Interactive डिब्बे खोजें: Shadow Lab (Section 03), Static Method Machine (04), एक Call, कई Drinks (05), Replace बनाम Extend (06) और Bug Doctor (09)। हर नतीजा असली Python runs से है।
请留意这些互动框:遮蔽实验室(第 03 节)、静态方法机器(04)、一次调用,多种饮品(05)、替换与扩展(06)和 Bug 医生(09)。每个结果都来自真实的 Python 运行。
Meet All Three at a Glance 👀तीनों से एक नज़र में मिलिए 👀一眼认识三者 👀
UPPER_SNAKE_CASE to say "don't reassign". Example: Drink.TAX_RATE = 0.10.UPPER_SNAKE_CASE में, ताकि पता चले "दोबारा assign न करें"। उदाहरण: Drink.TAX_RATE = 0.10।UPPER_SNAKE_CASE 命名,表示"不要重新赋值"。例如:Drink.TAX_RATE = 0.10。self and no cls — only their own arguments. Called on the class: Drink.celsius_to_fahrenheit(65). Good for validators, converters and pure calculations.self लेते हैं न cls — सिर्फ़ अपने arguments। Class पर बुलाए जाते हैं: Drink.celsius_to_fahrenheit(65)। Validators, converters और शुद्ध गणनाओं के लिए अच्छे।self,也不接收 cls — 只有自己的参数。在类上调用:Drink.celsius_to_fahrenheit(65)。适合校验器、换算器和纯计算。Static Variables — The Shop's Posted Rules 📌Static Variables — Shop के लगे हुए नियम 📌静态变量 — 店里张贴的规则 📌
A static variable is a value written directly under the class line, not inside __init__. There is exactly one copy in memory, and every instance reads it.
Static variable एक value है जो सीधे class line के नीचे लिखी जाती है, __init__ के अंदर नहीं। Memory में ठीक एक copy होती है, और हर instance उसे पढ़ता है।
静态变量是直接写在 class 行下面的值,而不是写在 __init__ 里。内存中只有 一份,每个实例都读取它。
class Drink:
# == STATIC VARIABLES - one copy, shared by every drink ==
STANDARD_CUP_ML = 250
MAX_BREW_TEMP_C = 95
TAX_RATE = 0.10
CURRENCY = "$"
def __init__(self, base_price):
# INSTANCE variables - one per drink
self.base_price = base_price
# Read via the class (the usual form)
print(Drink.STANDARD_CUP_ML)
print(Drink.TAX_RATE)
print(Drink.CURRENCY)
# Every instance sees the same value - it is not copied per drink
d1 = Drink(3); d2 = Drink(5); d3 = Drink(4)
print(d1.TAX_RATE, d2.TAX_RATE, d3.TAX_RATE)
print(d1.__dict__) # only base_price lives on the object
The last line shows that TAX_RATE is not stored on the drink. Python finds it on the class.
आख़िरी line दिखाती है कि TAX_RATE drink पर रखा ही नहीं है। Python उसे class पर पाता है।
最后一行表明 TAX_RATE 并不存放在饮品对象上。Python 是在类上找到它的。
Three drinks, three prices — but only one TAX_RATE. Change it on the class and every drink sees the new value.
तीन drinks, तीन prices — पर सिर्फ़ एक TAX_RATE। Class पर बदलें और हर drink नई value देखता है।
三杯饮品,三个价格 — 但只有一个 TAX_RATE。在类上修改,每杯饮品都会看到新值。
latte.TAX_RATE = 0.15 does not update the constant. It creates a per-instance shadow that only latte sees — every other drink still reads 0.1. To change a static value (rarely a good idea), do it through the class: Drink.TAX_RATE = 0.15.
latte.TAX_RATE = 0.15 constant को update नहीं करता। यह एक instance-वाला shadow बनाता है जो सिर्फ़ latte देखता है — बाक़ी हर drink अब भी 0.1 पढ़ता है। Static value बदलनी हो (जो कम ही अच्छा विचार है), तो class के ज़रिए बदलें: Drink.TAX_RATE = 0.15।
latte.TAX_RATE = 0.15 不会 更新常量。它只会创建一个只有 latte 能看到的实例级 遮蔽 — 其他饮品仍然读到 0.1。要修改静态值(很少是好主意),请通过类:Drink.TAX_RATE = 0.15。
class Drink:
TAX_RATE = 0.10
def __init__(self, base_price):
self.base_price = base_price
espresso, latte = Drink(3), Drink(5)
latte.TAX_RATE = 0.15 # WRONG: makes a shadow on latte only
print(latte.TAX_RATE, espresso.TAX_RATE, Drink.TAX_RATE)
print(latte.__dict__)
Drink.TAX_RATE = 0.12 # through the class: everyone without a shadow sees it
print(latte.TAX_RATE, espresso.TAX_RATE, Drink.TAX_RATE)
🪞 Simulator: Shadow Lab🪞 Simulator: Shadow Lab🪞 模拟器:遮蔽实验室
Run lines in any order. Each drink shows what drink.TAX_RATE reads and where it comes from. The two price rows show something surprising: the static method calculate_total reads Drink.TAX_RATE, so it ignores a shadow — but code that reads self.TAX_RATE does not. Checked against real Python on 300 random sequences.
Lines किसी भी क्रम में चलाएँ। हर drink दिखाता है कि drink.TAX_RATE क्या पढ़ता है और वह कहाँ से आता है। दो price rows एक हैरान करने वाली बात दिखाती हैं: static method calculate_total Drink.TAX_RATE पढ़ता है, इसलिए shadow को नज़रअंदाज़ करता है — पर self.TAX_RATE पढ़ने वाला code नहीं करता। असली Python से 300 random sequences पर जाँचा गया।
以任意顺序运行代码行。每杯饮品显示 drink.TAX_RATE 读到的值及其来源。两行价格揭示了一个意外:静态方法 calculate_total 读取的是 Drink.TAX_RATE,所以它会 忽略 遮蔽 — 而读取 self.TAX_RATE 的代码不会。已在 300 个随机序列上与真实 Python 核对。
Static Methods — The Shared Utility Shelf 🔧Static Methods — साझा औज़ारों की Shelf 🔧静态方法 — 共享的工具架 🔧
A static method is written with the @staticmethod decorator and takes no self and no cls. It is a plain function that happens to live inside the class. Use it for validators, converters, formatters and pure calculations.
Static method @staticmethod decorator के साथ लिखा जाता है और न self लेता है न cls। यह एक सादा function है जो बस class के अंदर रहता है। इसे validators, converters, formatters और शुद्ध गणनाओं के लिए इस्तेमाल करें।
静态方法用 @staticmethod 装饰器来写,不接收 self,也不接收 cls。它是一个恰好住在类里的普通函数。适合校验器、换算器、格式化函数和纯计算。
class Drink:
STANDARD_CUP_ML = 250
TAX_RATE = 0.10
def __init__(self, base_price):
self.base_price = base_price
# == STATIC METHOD - pure input -> output, no self, no cls ==
@staticmethod
def celsius_to_fahrenheit(c):
return c * 9 / 5 + 32
@staticmethod
def is_valid_size(size_ml):
return 25 <= size_ml <= 500
@staticmethod
def calculate_total(price):
# Uses the class-level constant - but needs no self or cls
return price * (1 + Drink.TAX_RATE)
# Call BEFORE any drink exists - that is the whole point
print(Drink.celsius_to_fahrenheit(65))
print(Drink.is_valid_size(200))
print(Drink.is_valid_size(1000))
print(Drink.calculate_total(5.00)) # with 10% tax
latte = Drink(5)
print(latte.celsius_to_fahrenheit(65)) # also works through an instance
Call it straight on the class. No instance is needed.
इसे सीधे class पर बुलाएँ। Instance की ज़रूरत नहीं।
直接在类上调用,不需要实例。
⚙️ Simulator: Static Method Machine⚙️ Simulator: Static Method Machine⚙️ 模拟器:静态方法机器
Pick a static method and drag the input. Then try two things: call it through an object, and remove the decorator. Every output matches real Python on the whole slider range.
कोई static method चुनें और input खिसकाएँ। फिर दो चीज़ें आज़माएँ: इसे object के ज़रिए बुलाएँ, और decorator हटा दें। हर output पूरी slider range पर असली Python से मिलता है।
选一个静态方法,拖动输入。然后试两件事:通过对象 调用它,以及 去掉装饰器。在整个滑块范围内,每个输出都与真实 Python 一致。
Method Overriding — Same Call, Different Behaviour 🔁Method Overriding — एक Call, अलग व्यवहार 🔁方法重写 — 同样的调用,不同的行为 🔁
Method overriding happens when a child class defines a method with the same name as one in its parent. When the method is called on the child, Python uses the child's version, and the parent's version is not used. This is what makes polymorphism possible: many types respond to the same command in different ways.
Method overriding तब होता है जब child class अपने parent जैसे नाम का method define करती है। Child पर method बुलाने पर Python child का version इस्तेमाल करता है, parent वाला नहीं। इसी से polymorphism संभव होता है: कई types एक ही आदेश पर अलग-अलग तरह से जवाब देते हैं।
当子类定义了一个与父类方法 同名 的方法时,就发生了 方法重写。在子类上调用该方法时,Python 使用 子类的版本,父类的版本不会被用到。这让 多态 成为可能:多种类型对同一个命令做出不同的响应。
class Drink:
def __init__(self, size_ml, base_price):
self.size_ml = size_ml
self.base_price = base_price
# A generic prepare() - subclasses will override this
def prepare(self):
print("Preparing a generic drink - hot water in a cup.")
class Espresso(Drink):
# -- OVERRIDE - same name, brand-new implementation --
def prepare(self):
print(f"Espresso ({self.size_ml}ml): grind beans, tamp, extract 25s.")
class Latte(Drink):
def prepare(self):
print(f"Latte ({self.size_ml}ml): pull espresso, steam milk to 65°C, pour art.")
class Cappuccino(Drink):
def prepare(self):
print(f"Cappuccino ({self.size_ml}ml): equal parts espresso, milk, foam.")
# Same call, different result - that is polymorphism
for drink in [Espresso(30, 3), Latte(250, 5), Cappuccino(180, 4.5)]:
drink.prepare()
print([c.__name__ for c in Espresso.mro()]) # where Python searches
When you call obj.method(), Python starts searching at the object's own class. The first match wins. If Espresso defines prepare(), Python uses it and never looks at Drink.prepare(). The search order is the Method Resolution Order (MRO) — the last line above prints it.
जब आप obj.method() बुलाते हैं, Python object की अपनी class से खोज शुरू करता है। पहला match जीतता है। अगर Espresso में prepare() है, तो Python उसे इस्तेमाल करता है और Drink.prepare() को देखता तक नहीं। खोज का यह क्रम Method Resolution Order (MRO) है — ऊपर की आख़िरी line इसे print करती है।
调用 obj.method() 时,Python 从对象自己的类开始查找。第一个匹配的胜出。如果 Espresso 定义了 prepare(),Python 就用它,根本不会去看 Drink.prepare()。这个查找顺序就是 方法解析顺序(MRO) — 上面最后一行把它打印了出来。
The loop calls prepare() on each drink in turn. Python picks the right prepare() for each one — the parent's generic version never runs.
Loop हर drink पर बारी-बारी prepare() बुलाता है। Python हर एक के लिए सही prepare() चुनता है — parent का generic version कभी नहीं चलता।
循环依次对每杯饮品调用 prepare()。Python 为每一杯挑选正确的 prepare() — 父类的通用版本从不运行。
🍹 Simulator: One Call, Many Drinks🍹 Simulator: एक Call, कई Drinks🍹 模拟器:一次调用,多种饮品
These are the classes from the complete example in Section 07. Pick a drink to see where prepare() and price_receipt() are found. Then build a menu and press Run loop: the same drink.prepare() call goes to a different class each time. All outputs are real.
ये Section 07 के पूरे उदाहरण की classes हैं। कोई drink चुनें और देखें कि prepare() और price_receipt() कहाँ मिलते हैं। फिर menu बनाएँ और Run loop दबाएँ: वही drink.prepare() call हर बार अलग class तक जाती है। सभी outputs असली हैं।
这些是第 07 节完整示例中的类。选一杯饮品,看看 prepare() 和 price_receipt() 在哪里被找到。然后搭一份菜单,按 Run loop:同一个 drink.prepare() 调用每次都会走到不同的类。所有输出都是真实的。
Override + Extend — Using super() to Keep the Parent's Behaviour 🧩Override + Extend — Parent का व्यवहार रखने के लिए super() 🧩重写 + 扩展 — 用 super() 保留父类行为 🧩
Sometimes you do not want to replace the parent's method — you want to extend it. Call super().method() inside your override to run the parent's version first, then add your own steps.
कभी-कभी आप parent का method replace नहीं करना चाहते — उसे extend करना चाहते हैं। अपने override के अंदर super().method() बुलाएँ ताकि पहले parent का version चले, फिर अपने steps जोड़ें।
有时你并不想 替换 父类的方法 — 而是想 扩展 它。在你的重写中调用 super().method(),先运行父类版本,再加上你自己的步骤。
class Drink:
def __init__(self, size_ml, base_price):
self.size_ml = size_ml
self.base_price = base_price
def prepare(self):
print(" 1. Warm the cup")
print(" 2. Fill with liquid")
class FlavouredLatte(Drink):
def __init__(self, size_ml, base_price, syrup):
super().__init__(size_ml, base_price)
self.syrup = syrup
def prepare(self):
super().prepare() # run the parent's steps first
print(f" 3. Add {self.syrup} syrup") # then extend
print(" 4. Steam milk and pour")
drink = FlavouredLatte(250, 5.50, syrup="vanilla")
drink.prepare()
Replace — override without calling super(). The parent's version never runs. Use it when the child's behaviour is completely different. Extend — override and call super().method() inside. The parent runs, then your addition runs. Use it for "the parent's logic plus a bit more".
Replace — super() बुलाए बिना override। Parent का version कभी नहीं चलता। तब इस्तेमाल करें जब child का व्यवहार बिल्कुल अलग हो। Extend — override करें और अंदर super().method() बुलाएँ। पहले parent चलता है, फिर आपका जोड़। "Parent का logic और थोड़ा ज़्यादा" के लिए इस्तेमाल करें।
替换 — 重写时不调用 super()。父类版本永远不运行。适用于子类行为完全不同的情况。扩展 — 重写 并且 在里面调用 super().method()。先运行父类,再运行你的追加部分。适用于"父类逻辑再多一点"。
Without super() the parent's two steps are lost. With super() they run first, then the child's steps.
super() के बिना parent के दो steps खो जाते हैं। super() के साथ वे पहले चलते हैं, फिर child के steps।
没有 super(),父类的两个步骤就丢了。有 super(),它们先运行,然后才是子类的步骤。
🧩 Simulator: Replace vs Extend🧩 Simulator: Replace बनाम Extend🧩 模拟器:替换与扩展
Switch between the two versions of FlavouredLatte.prepare() and step through each. With extend, watch super().prepare() open the parent's frame on top of the stack, print steps 1–2, then return. With replace, the parent's prepare() is never called. Recorded with sys.settrace.
FlavouredLatte.prepare() के दोनों versions में बदलें और हर एक को step करें। Extend में देखें कि super().prepare() stack के ऊपर parent का frame खोलता है, steps 1–2 print करता है, फिर लौटता है। Replace में parent का prepare() कभी बुलाया ही नहीं जाता। sys.settrace से रिकॉर्ड।
在 FlavouredLatte.prepare() 的两个版本之间切换,并逐步运行。在 扩展 版本中,看 super().prepare() 在栈顶打开父类的帧,打印第 1–2 步,然后返回。在 替换 版本中,父类的 prepare() 根本不会被调用。由 sys.settrace 记录。
Putting All Three Together — The Complete Coffee Shop 🏪तीनों एक साथ — पूरी Coffee Shop 🏪三者合一 — 完整的咖啡店 🏪
One family of classes that uses static variables (shop rules), static methods (utility functions) and method overriding (each drink's own preparation). This is the real payoff.
Classes का एक परिवार जो static variables (shop के नियम), static methods (utility functions) और method overriding (हर drink का अपना तरीक़ा) इस्तेमाल करता है। यही असली फ़ायदा है।
一个类家族,同时使用静态变量(店规)、静态方法(工具函数)和方法重写(每款饮品自己的做法)。这才是真正的收获。
class Drink:
# == STATIC VARIABLES - shared across every drink and every subclass ==
STANDARD_CUP_ML = 250
MAX_BREW_TEMP_C = 95
TAX_RATE = 0.10
CURRENCY = "$"
def __init__(self, size_ml, base_price):
if not Drink.is_valid_size(size_ml): # uses a STATIC METHOD
raise ValueError(f"{size_ml}ml is out of range")
self.size_ml = size_ml
self.base_price = base_price
# -- Generic prepare - subclasses OVERRIDE this --
def prepare(self):
print("Generic drink: hot water, done.")
# -- Instance method - uses a static variable for its calculation --
def price_receipt(self):
total = Drink.calculate_total(self.base_price)
return f" Price: {Drink.CURRENCY}{self.base_price:.2f} + tax → {Drink.CURRENCY}{total:.2f}"
# == STATIC METHODS - utility functions grouped with the class ==
@staticmethod
def is_valid_size(size_ml):
return 25 <= size_ml <= 500
@staticmethod
def celsius_to_fahrenheit(c):
return c * 9 / 5 + 32
@staticmethod
def calculate_total(price):
return price * (1 + Drink.TAX_RATE)
class Espresso(Drink):
def __init__(self):
super().__init__(size_ml=30, base_price=3.00)
# OVERRIDE - Espresso has its own steps
def prepare(self):
print(f"[Espresso {self.size_ml}ml] grind → tamp → extract for 25s")
class Latte(Drink):
def __init__(self):
super().__init__(size_ml=250, base_price=5.00)
def prepare(self):
temp_f = Drink.celsius_to_fahrenheit(65) # uses a STATIC METHOD
print(f"[Latte {self.size_ml}ml] pull espresso → steam milk to 65°C ({temp_f}°F) → pour art")
class Cappuccino(Drink):
def __init__(self):
super().__init__(size_ml=180, base_price=4.50)
def prepare(self):
print(f"[Cappuccino {self.size_ml}ml] equal parts espresso + steamed milk + foam")
class FlavouredLatte(Latte):
def __init__(self, syrup):
super().__init__()
self.syrup = syrup
self.base_price += 0.75 # flavour surcharge
# OVERRIDE + EXTEND - run the parent's Latte prepare, then add the syrup step
def prepare(self):
super().prepare()
print(f" → finish with {self.syrup} syrup")
# -- Use the static methods BEFORE any drink exists --
print("Valid 150ml cup?", Drink.is_valid_size(150))
print("Valid 900ml cup?", Drink.is_valid_size(900))
print("Brew temp in F:", Drink.celsius_to_fahrenheit(Drink.MAX_BREW_TEMP_C))
print()
# -- Same loop, each drink runs its own prepare() --
menu = [Espresso(), Latte(), Cappuccino(), FlavouredLatte(syrup="vanilla")]
for drink in menu:
drink.prepare() # goes to the right override
print(drink.price_receipt()) # inherited from Drink, uses a static var + method
print()
Static variables (TAX_RATE, CURRENCY, MAX_BREW_TEMP_C) hold the one-truth constants. Static methods (is_valid_size, celsius_to_fahrenheit, calculate_total) are utilities every drink can call — even __init__ uses one to reject a bad size. Method overriding gives each drink its own prepare(). And FlavouredLatte shows "override + extend" with super().prepare().
Static variables (TAX_RATE, CURRENCY, MAX_BREW_TEMP_C) एक-सच वाले constants रखते हैं। Static methods (is_valid_size, celsius_to_fahrenheit, calculate_total) utilities हैं जिन्हें हर drink बुला सकता है — __init__ भी ग़लत size ठुकराने के लिए एक इस्तेमाल करता है। Method overriding हर drink को अपना prepare() देता है। और FlavouredLatte super().prepare() से "override + extend" दिखाता है।
静态变量(TAX_RATE、CURRENCY、MAX_BREW_TEMP_C)保存唯一可信的常量。静态方法(is_valid_size、celsius_to_fahrenheit、calculate_total)是每杯饮品都能调用的工具 — 连 __init__ 也用它来拒绝不合法的容量。方法重写 让每款饮品有自己的 prepare()。FlavouredLatte 则用 super().prepare() 展示了"重写 + 扩展"。
When to Reach for Each Tool — Decision Grid 🧭कब कौन-सा Tool — Decision Grid 🧭何时用哪个工具 — 决策表 🧭
self nor cls, but still belongs with the class — validators, converters, formatters, pure calculations. Grouping them keeps them easy to find.self चाहिए न cls, फिर भी वह class से जुड़ा है — validators, converters, formatters, शुद्ध गणनाएँ। साथ रखने से वे आसानी से मिलते हैं।self 也不需要 cls,但在概念上属于这个类 — 校验器、换算器、格式化函数、纯计算。放在一起便于查找。super().method(...) inside the override, then add your own steps.super().method(...) बुलाएँ, फिर अपने steps जोड़ें।super().method(...),然后加上你自己的步骤。list or dict is shared by every instance. One .append() hits them all. Put per-instance data in __init__.list या dict हर instance साझा करता है। एक .append() सब पर असर डालता है। हर instance का data __init__ में रखें।list 或 dict 被 所有实例 共享。一次 .append() 就会影响全部。每个实例自己的数据放在 __init__ 里。Common Mistakes (and Fixes) 🩹आम ग़लतियाँ (और उनके हल) 🩹常见错误(及修正)🩹
| Mistakeग़लती错误 | What goes wrongक्या बिगड़ता है会出什么问题 | Fixहल修正 |
|---|---|---|
Adding self to a static methodStatic method में self जोड़ना给静态方法加了 self | It now needs an object; calling it on the class raises TypeErrorअब इसे object चाहिए; class पर बुलाने से TypeError现在它需要对象;在类上调用会抛出 TypeError | Drop self; add @staticmethod on the line aboveself हटाएँ; ऊपर वाली line पर @staticmethod जोड़ें去掉 self;在上一行加 @staticmethod |
Forgetting @staticmethod@staticmethod भूलना忘写 @staticmethod | Calling through the class still works, so it hides; calling through an object passes the object as the first argument → TypeErrorClass के ज़रिए call चलती है, इसलिए छिपा रहता है; object के ज़रिए call में object पहला argument बनता है → TypeError通过类调用仍然能用,所以问题被掩盖;通过对象调用时对象被当作第一个参数 → TypeError | Add @staticmethod — the decorator is required@staticmethod जोड़ें — decorator ज़रूरी है加上 @staticmethod — 装饰器是必需的 |
instance.CONSTANT = value | Creates a per-instance shadow — the class constant stays the sameInstance-वाला shadow बनता है — class constant वैसा ही रहता है产生实例级遮蔽 — 类常量保持不变 | Never write it. To change it, go through the class: Drink.TAX_RATE = ...कभी न लिखें। बदलना हो तो class के ज़रिए: Drink.TAX_RATE = ...永远不要这样写。要修改就通过类:Drink.TAX_RATE = ... |
A mutable static variable (orders = [])Mutable static variable (orders = [])可变的静态变量(orders = []) | Every instance shares one list; a change from any of them reaches allहर instance एक list साझा करता है; किसी का भी बदलाव सब तक पहुँचता है所有实例共享一个列表;任何一个的修改都会影响全部 | Put it in __init__: self.orders = []इसे __init__ में रखें: self.orders = []放进 __init__:self.orders = [] |
| Overriding with a different signatureअलग signature के साथ override करना重写时签名不一致 | Code that calls the parent's way fails on the child with TypeErrorParent वाले तरीक़े से बुलाने वाला code child पर TypeError से fail होता है按父类方式调用的代码在子类上抛出 TypeError | Keep the same parameters; give any new ones a defaultवही parameters रखें; नए parameters को default दें保持参数一致;新增参数给默认值 |
Overriding but forgetting super() when you meant to extendExtend करना था पर override में super() भूल गए想扩展,重写时却忘了 super() | The parent's steps are silently skippedParent के steps चुपचाप छूट जाते हैं父类的步骤被悄悄跳过 | Decide on purpose: replace (no super()) or extend (call super())सोच-समझकर तय करें: replace (super() नहीं) या extend (super() बुलाएँ)有意识地决定:替换(不调用 super())还是扩展(调用 super()) |
| Overriding when a setting would doजहाँ setting काफ़ी हो वहाँ override करना本可以用一个设置,却去重写 | Lots of one-line subclasses (class RedButton(Button))बहुत सी एक-line वाली subclasses (class RedButton(Button))大量只有一行的子类(class RedButton(Button)) | Use a parameter or class variable in the parent insteadइसकी जगह parent में parameter या class variable इस्तेमाल करें改为在父类中使用参数或类变量 |
🩺 Simulator: Bug Doctor🩺 Simulator: Bug Doctor🩺 模拟器:Bug 医生
Six of these mistakes, run for real. Buggy code on the left, fixed code on the right, changed lines marked. Three of them give no error at all.
इनमें से छह ग़लतियाँ, असली run में। बाईं ओर buggy code, दाईं ओर ठीक किया हुआ, बदली lines चिह्नित। इनमें से तीन कोई error नहीं देतीं।
其中六个错误的真实运行。左边是有 bug 的代码,右边是修正后的代码,改动的行已标出。其中三个 完全不报错。
Quick Reference 📋Quick Reference 📋速查表 📋
| Taskकाम任务 | SyntaxSyntax语法 | Notesनोट说明 |
|---|---|---|
| Declare a static variableStatic variable declare करना声明静态变量 | TAX_RATE = 0.10 under the class lineclass line के नीचे TAX_RATE = 0.10在 class 行下写 TAX_RATE = 0.10 | UPPER_SNAKE_CASE; treat it as read-onlyUPPER_SNAKE_CASE; इसे सिर्फ़ पढ़ने वाला मानेंUPPER_SNAKE_CASE;当作只读 |
| Read a static variableStatic variable पढ़ना读取静态变量 | Drink.TAX_RATE | The usual formसामान्य रूप常用写法 |
| Change a static variableStatic variable बदलना修改静态变量 | Drink.TAX_RATE = 0.12 | ⚠️ Never through an instance⚠️ Instance के ज़रिए कभी नहीं⚠️ 绝不要通过实例 |
| Declare a static methodStatic method declare करना声明静态方法 | @staticmethod + def fn(x): | Decorator on the line above defDecorator def के ऊपर वाली line पर装饰器写在 def 上一行 |
| Call a static methodStatic method बुलाना调用静态方法 | Drink.is_valid_size(200) | No instance neededInstance की ज़रूरत नहीं不需要实例 |
| Override a methodMethod override करना重写方法 | Redefine it with the same name in the childChild में उसी नाम से दोबारा define करें在子类中用相同名字重新定义 | The child's version winsChild का version जीतता है子类版本胜出 |
| Extend a methodMethod extend करना扩展方法 | Override + call super().method(...)Override + super().method(...) बुलाएँ重写 + 调用 super().method(...) | Parent runs, then your additionपहले parent, फिर आपका जोड़先运行父类,再运行你的追加 |
| Polymorphic loopPolymorphic loop多态循环 | for x in items: x.prepare() | Each object goes to its own overrideहर object अपने override तक जाता है每个对象都调用自己的重写版本 |
| See the lookup orderखोज का क्रम देखना查看查找顺序 | Espresso.mro() | The first class in the list that defines the method winsList में जिस पहली class में method है, वही जीतती है列表中第一个定义该方法的类胜出 |
Golden Rules and Quiz 🏆सुनहरे नियम और Quiz 🏆黄金法则与小测验 🏆
UPPER_SNAKE_CASE to say "don't reassign".UPPER_SNAKE_CASE रखें।UPPER_SNAKE_CASE 命名,表示"不要重新赋值"。Drink.TAX_RATE. Writing through an instance (d.TAX_RATE = 0.15) does not change the constant — it creates a silent shadow on that one object.Drink.TAX_RATE। Instance के ज़रिए लिखने (d.TAX_RATE = 0.15) से constant नहीं बदलता — उस एक object पर चुपचाप shadow बनता है।Drink.TAX_RATE。通过实例写入(d.TAX_RATE = 0.15)不会 改变常量 — 只会在那个对象上悄悄产生遮蔽。self nor cls. If it needs instance data, make it an instance method. If it needs the class, make it a class method. Only when it needs neither is it truly static.self लेता है न cls। Instance data चाहिए तो instance method बनाएँ। Class चाहिए तो class method। जब दोनों में से कुछ न चाहिए, तभी वह सच में static है।self 也不接收 cls。需要实例数据就写成实例方法;需要类就写成类方法。只有两者都不需要时,才真正是静态的。@staticmethod on the line above def. Without it, calling through the class still works, but calling through an object passes the object as an extra first argument and raises TypeError.@staticmethod हमेशा def के ऊपर वाली line पर रखें। इसके बिना class के ज़रिए call फिर भी चलती है, पर object के ज़रिए call में object अतिरिक्त पहले argument के रूप में जाता है और TypeError आता है।@staticmethod 写在 def 上一行。没有它,通过类调用仍然可行,但通过对象调用会把对象当作多余的第一个参数传入,抛出 TypeError。@staticmethod for validators, converters, formatters and pure calculations that belong with the class. If a function has nothing to do with the class, keep it as a normal module function.@staticmethod को उन validators, converters, formatters और शुद्ध गणनाओं के लिए इस्तेमाल करें जो class से जुड़ी हैं। अगर function का class से कोई लेना-देना नहीं, तो उसे सामान्य module function रखें।@staticmethod 用于与类相关的 校验器、换算器、格式化函数和纯计算。如果函数与类无关,就保留为普通的模块函数。super(). Extending = call super().method(...) inside the override so the parent's logic still runs.super() नहीं। Extend = override के अंदर super().method(...) बुलाएँ ताकि parent का logic भी चले।super()。扩展 = 在重写中调用 super().method(...),让父类逻辑依然运行。Quick Quiz — 8 Questionsछोटा Quiz — 8 सवाल小测验 — 8 道题
Static variables are one shared set of rules — read them anywhere, change them only through the class. Static methods are plain tools that need no self or cls, so you can call them before any object exists. Method overriding lets one call, drink.prepare(), do the right thing for every subclass — replace the parent's version, or extend it with super().
Static variables नियमों का एक साझा सेट हैं — कहीं भी पढ़ें, बदलें सिर्फ़ class के ज़रिए। Static methods सादे औज़ार हैं जिन्हें न self चाहिए न cls, इसलिए उन्हें किसी object के बनने से पहले भी बुला सकते हैं। Method overriding से एक ही call, drink.prepare(), हर subclass के लिए सही काम करती है — parent का version replace करें, या super() से extend करें।
静态变量是一套共享的规则 — 哪里都能读,只通过类来改。静态方法是不需要 self 或 cls 的普通工具,所以在任何对象存在之前就能调用。方法重写让同一个调用 drink.prepare() 对每个子类都做对的事 — 替换父类版本,或用 super() 扩展它。