The Story That Explains These Three Tools ☕इन तीन Tools को समझाने वाली कहानी ☕一个讲清这三个工具的故事 ☕
Each store has its own cash register, its own daily revenue and its own baristas. These are instance variables — different for every store.
But every store shares the same menu, the same prices and the same logo. These are class variables — one truth for the whole chain.
When a customer orders a latte in Mumbai, only the Mumbai store's revenue moves. That is an instance method — behaviour that runs on one store. When HQ raises the latte price from $4.50 to $5.00, every store has the new price at once. That is a class method — one call, the whole chain updates.
हर store का अपना cash register, अपना रोज़ का revenue और अपने baristas हैं। ये instance variables हैं — हर store के लिए अलग।
पर हर store का menu, prices और logo एक ही है। ये class variables हैं — पूरी chain के लिए एक ही सच।
जब Mumbai में कोई customer latte मँगाता है, तो सिर्फ़ Mumbai store का revenue बदलता है। यह instance method है — एक store पर चलने वाला व्यवहार। जब HQ latte की price $4.50 से $5.00 करता है, तो हर store पर नई price तुरंत लागू हो जाती है। यह class method है — एक call, पूरी chain update।
每家店都有自己的收银机、自己的日营业额和自己的咖啡师。这些是 实例变量 — 每家店各不相同。
但所有门店共用同一份菜单、同样的价格和同一个标志。这些是 类变量 — 整个连锁只有一份。
顾客在孟买店点一杯拿铁,只有孟买店的营业额变化。这就是 实例方法 — 作用于某一家店的行为。总部把拿铁从 $4.50 提价到 $5.00,所有门店立刻生效。这就是 类方法 — 一次调用,整个连锁都更新。
Instance methods = behaviour of one object. Class variables = data shared by every object. Class methods = behaviour that acts on the class itself (or creates new objects). Master these three and you can model almost any real-world problem in Python.
Instance methods = एक object का व्यवहार। Class variables = हर object का साझा data। Class methods = ख़ुद class पर काम करने वाला व्यवहार (या नए objects बनाने वाला)। इन तीनों में माहिर हो जाएँ, तो आप Python में लगभग हर असली समस्या को model कर सकते हैं।
实例方法 = 单个对象的行为。类变量 = 所有对象共享的数据。类方法 = 作用于类本身的行为(或用于创建新对象)。掌握这三者,你几乎能用 Python 为任何现实问题建模。
Look for the interactive boxes: the Attribute Lookup Lab (Section 05), Who Receives What? (06), the Coffee Chain Simulator (09) and the Bug Doctor (11). The lab and the chain were checked against real Python on hundreds of random runs.
Interactive डिब्बे खोजें: Attribute Lookup Lab (Section 05), किसे क्या मिलता है? (06), Coffee Chain Simulator (09) और Bug Doctor (11)। Lab और chain को सैकड़ों random runs पर असली Python से जाँचा गया।
请留意这些互动框:属性查找实验室(第 05 节)、谁接收了什么?(06)、咖啡连锁模拟器(09)和 Bug 医生(11)。实验室和连锁模拟器已在数百次随机运行中与真实 Python 核对过。
Where We Are — What You Already Know 🧭हम कहाँ हैं — जो आप पहले से जानते हैं 🧭我们在哪里 — 你已经掌握的内容 🧭
You already know how to write a class with __init__ and instance variables:
आप पहले से जानते हैं कि __init__ और instance variables वाली class कैसे लिखते हैं:
你已经会写带有 __init__ 和实例变量的类了:
class CoffeeShop:
def __init__(self, city, staff_count):
self.city = city # instance variable - per store
self.staff_count = staff_count # instance variable - per store
self.daily_revenue = 0.0 # instance variable - per store
store1 = CoffeeShop("Mumbai", 8)
store2 = CoffeeShop("London", 12)
print(store1.__dict__)
print(store2.__dict__)
This gives you objects that hold data. Next we need three more things: objects that can also do things (instance methods), data that every object shares (class variables), and methods that belong to the class itself (class methods). One at a time.
इससे ऐसे objects मिलते हैं जो data रखते हैं। अब हमें तीन और चीज़ें चाहिए: ऐसे objects जो काम भी कर सकें (instance methods), ऐसा data जो हर object साझा करे (class variables), और ऐसे methods जो ख़ुद class के हों (class methods)। एक-एक करके।
这样得到的对象能 保存数据。接下来还需要三样东西:能 做事 的对象(实例方法)、所有 对象共享的数据(类变量),以及属于 类本身 的方法(类方法)。我们一个一个来。
Normal Methods (Instance Methods) — Behaviour of Each Object 🛠️सामान्य Methods (Instance Methods) — हर Object का व्यवहार 🛠️普通方法(实例方法)— 每个对象的行为 🛠️
A normal method — also called an instance method — is a function written inside a class whose first parameter is self. When you call obj.method(), Python passes obj in as self, so the method knows which object it is working on.
सामान्य method — जिसे instance method भी कहते हैं — class के अंदर लिखा ऐसा function है जिसका पहला parameter self है। जब आप obj.method() बुलाते हैं, Python obj को self के रूप में भेजता है, ताकि method को पता रहे कि वह किस object पर काम कर रहा है।
普通方法(也叫 实例方法)是写在类里、第一个参数为 self 的函数。调用 obj.method() 时,Python 把 obj 作为 self 传进去,于是方法知道自己在处理哪个对象。
def serve(self, item, price):
Class body के अंदर लिखा: def serve(self, item, price):
写在类体内:def serve(self, item, price):
self — receives the object the method was called on
self — वह object पाता है जिस पर method बुलाया गया
self — 接收调用该方法的对象
self.x to read and write that object's own instance variables
उस object के अपने instance variables पढ़ने-लिखने के लिए self.x
用 self.x 读写该对象自己的实例变量
mumbai.serve("latte", 4.5) — Python passes mumbai as self
mumbai.serve("latte", 4.5) — Python mumbai को self बनाकर भेजता है
mumbai.serve("latte", 4.5) — Python 把 mumbai 作为 self 传入
class CoffeeShop:
def __init__(self, city):
self.city = city
self.daily_revenue = 0.0
self.orders = []
# -- Normal (instance) method: acts on THIS store --
def serve(self, item, price):
self.daily_revenue += price
self.orders.append(item)
print(f"[{self.city}] Served {item} for ${price}")
# -- Another instance method that reports state --
def summary(self):
print(f"{self.city}: {len(self.orders)} orders, ${self.daily_revenue}")
mumbai = CoffeeShop("Mumbai")
london = CoffeeShop("London")
mumbai.serve("latte", 4.5) # self = mumbai
mumbai.serve("muffin", 3.5) # self = mumbai
london.serve("espresso", 3.0) # self = london
mumbai.summary() # uses Mumbai's data only
london.summary() # uses London's data only
Notice $4.5 and $8.0: an f-string prints a float as it is, without a fixed number of decimals. Section 09 uses :.2f to always show two.
$4.5 और $8.0 देखें: f-string float को जैसा है वैसा print करती है, तय decimals के बिना। Section 09 हमेशा दो decimals दिखाने के लिए :.2f इस्तेमाल करता है।
注意 $4.5 和 $8.0:f-string 按原样打印浮点数,不固定小数位。第 09 节用 :.2f 来始终显示两位小数。
Python passes mumbai in as self, so only Mumbai's revenue moves. London and Tokyo are never touched.
Python mumbai को self बनाकर भेजता है, इसलिए सिर्फ़ Mumbai का revenue बदलता है। London और Tokyo को छुआ तक नहीं जाता।
Python 把 mumbai 作为 self 传入,所以只有孟买的营业额变化。伦敦和东京完全没被碰到。
Class Variables — One Copy, Shared by Every Object 📋Class Variables — एक Copy, हर Object साझा करता है 📋类变量 — 只有一份,所有对象共享 📋
A class variable is written at the class level, not inside __init__. There is exactly one copy, and every instance can see it. Think of it as "facts about the idea of a coffee shop, not about any one shop".
Class variable class के स्तर पर लिखा जाता है, __init__ के अंदर नहीं। इसकी ठीक एक copy होती है, और हर instance इसे देख सकता है। इसे ऐसे सोचें: "coffee shop के विचार से जुड़े तथ्य, किसी एक shop के नहीं"।
类变量 写在类的层级上,而不是 __init__ 里。它只有一份,所有实例都能看到。可以把它理解为"属于咖啡店这个概念的事实,而不是某一家店的"。
class CoffeeShop:
# -- Class variables: declared at the class level, ONE copy total --
company_name = "Bean There"
menu = {"latte": 4.50, "espresso": 3.00, "muffin": 3.50}
total_stores = 0
def __init__(self, city):
# -- Instance variables: one copy per object --
self.city = city
self.daily_revenue = 0.0
CoffeeShop.total_stores += 1 # bump the shared counter
mumbai = CoffeeShop("Mumbai")
london = CoffeeShop("London")
tokyo = CoffeeShop("Tokyo")
# Read class variables through the class itself
print(CoffeeShop.company_name)
print(CoffeeShop.total_stores)
print(CoffeeShop.menu["latte"])
# You CAN also read them through any instance - they are shared
print(mumbai.company_name)
print(london.menu["latte"])
print(london.menu is CoffeeShop.menu) # the very same dict object
print(mumbai.__dict__) # the class variables are NOT in here
The last line is the key: mumbai.__dict__ holds only city and daily_revenue. When you read mumbai.company_name, Python does not find it on the object, so it looks on the class. That is why one copy is enough.
आख़िरी line सबसे अहम है: mumbai.__dict__ में सिर्फ़ city और daily_revenue हैं। जब आप mumbai.company_name पढ़ते हैं, Python को यह object पर नहीं मिलता, तो वह class पर देखता है। इसीलिए एक copy काफ़ी है।
最后一行是关键:mumbai.__dict__ 里只有 city 和 daily_revenue。读取 mumbai.company_name 时,Python 在对象上找不到,就去类上找。所以一份就够了。
Class variable — one copy in total, shared. Written directly under the class line: menu = {...}. Instance variable — one copy per object. Written with self. inside a method: self.city = city.
Class variable — कुल एक copy, साझा। सीधे class line के नीचे लिखा: menu = {...}। Instance variable — हर object की एक copy। Method के अंदर self. के साथ लिखा: self.city = city।
类变量 — 总共一份,共享。直接写在 class 行下面:menu = {...}。实例变量 — 每个对象一份。在方法里用 self. 写:self.city = city。
First HQ changes the shared menu, and all three stores read 5.0. Then Mumbai sells one latte for 5.0: only Mumbai's revenue moves.
पहले HQ साझा menu बदलता है, और तीनों stores 5.0 पढ़ते हैं। फिर Mumbai 5.0 में एक latte बेचता है: सिर्फ़ Mumbai का revenue बदलता है।
先是总部修改共享菜单,三家店都读到 5.0。然后孟买以 5.0 卖出一杯拿铁:只有孟买的营业额变化。
The Two Gotchas of Class Variables ⚠️Class Variables के दो जाल ⚠️类变量的两个陷阱 ⚠️
Class variables are simple — until you change them the wrong way. Two traps catch almost every beginner. Both come from one rule: reading falls back to the class, but writing through an object creates an instance variable.
Class variables आसान हैं — जब तक आप उन्हें ग़लत तरीक़े से न बदलें। दो जाल लगभग हर beginner को पकड़ते हैं। दोनों एक ही नियम से आते हैं: पढ़ते समय Python class पर जाता है, पर object के ज़रिए लिखने से instance variable बनता है।
类变量很简单 — 直到你用错误的方式修改它们。有两个陷阱几乎每个初学者都会踩。它们都来自同一条规则:读取时会退回到类上找,但通过对象写入会创建实例变量。
Gotcha #1 — Writing Through an Instance Creates a Shadowजाल #1 — Instance के ज़रिए लिखने से Shadow बनता है陷阱 #1 — 通过实例写入会产生遮蔽
class CoffeeShop:
total_stores = 0 # class variable
s1 = CoffeeShop()
s2 = CoffeeShop()
# WRONG: this does NOT update the shared counter
s1.total_stores = 99 # creates a NEW instance variable on s1
print(s1.total_stores) # s1's own attribute (the shadow)
print(s2.total_stores) # s2 still reads the class variable
print(CoffeeShop.total_stores) # the class variable is untouched
print(s1.__dict__, s2.__dict__)
# RIGHT: update through the class itself
CoffeeShop.total_stores = 50
print(s2.total_stores) # s2 sees the new value
print(s1.total_stores) # s1 still sees its own shadow!
s1 now has its own total_stores, so reading stops there. s2 has none, so Python goes on to the class.
s1 के पास अब अपना total_stores है, इसलिए पढ़ना वहीं रुक जाता है। s2 के पास नहीं है, इसलिए Python class तक जाता है।
s1 现在有了自己的 total_stores,读取就停在那里。s2 没有,于是 Python 继续去类上找。
Writing instance.attr = value always creates an instance variable — even if a class variable with the same name exists. To change a class variable, write it through the class: ClassName.attr = value.
instance.attr = value लिखने से हमेशा instance variable बनता है — भले ही उसी नाम का class variable मौजूद हो। Class variable बदलने के लिए class के ज़रिए लिखें: ClassName.attr = value।
写 instance.attr = value 总是 创建实例变量 — 即使存在同名的类变量。要修改类变量,请通过类来写:ClassName.attr = value。
Gotcha #2 — Mutable Class Variables Are Shared Stateजाल #2 — Mutable Class Variables साझा State हैं陷阱 #2 — 可变类变量是共享状态
class CoffeeShop:
orders = [] # class variable - a list (mutable!)
def __init__(self, city):
self.city = city
s1 = CoffeeShop("Mumbai")
s2 = CoffeeShop("London")
s1.orders.append("latte") # changes the SHARED list in place
print(s1.orders)
print(s2.orders) # London "has" Mumbai's order!
print(s1.orders is s2.orders) # the same list object
No = was used, so no shadow was made. .append() changed the one list that lives on the class. The fix is to create the list in __init__:
कोई = इस्तेमाल नहीं हुआ, इसलिए shadow नहीं बना। .append() ने class पर रहने वाली एक ही list बदल दी। हल है list को __init__ में बनाना:
这里没有用 =,所以没有产生遮蔽。.append() 修改了类上那唯一的列表。修正方法是在 __init__ 里创建列表:
class CoffeeShop:
def __init__(self, city):
self.city = city
self.orders = [] # FIX: a fresh list for every store
s1 = CoffeeShop("Mumbai")
s2 = CoffeeShop("London")
s1.orders.append("latte")
print(s1.orders, s2.orders, s1.orders is s2.orders)
Never use a mutable object (list, dict, set) as a class variable unless you really want every instance to share and change the same one. For per-object lists, create them in __init__: self.orders = []. Use class variables for shared data that does not change in place — strings, numbers, tuples — or for things that truly belong to everyone, like the menu.
Mutable object (list, dict, set) को class variable तभी बनाएँ जब आप सच में चाहते हों कि हर instance उसी एक को साझा करे और बदले। हर object की अपनी list __init__ में बनाएँ: self.orders = []। Class variables उस साझा data के लिए रखें जो अपनी जगह नहीं बदलता — strings, numbers, tuples — या उन चीज़ों के लिए जो सच में सबकी हैं, जैसे menu।
除非你真的希望所有实例共享并修改同一个对象,否则不要把可变对象(list、dict、set)作为类变量。每个对象自己的列表应在 __init__ 里创建:self.orders = []。类变量适合不会原地修改的共享数据 — 字符串、数字、元组 — 或者真正属于所有人的东西,比如菜单。
🔬 Simulator: Attribute Lookup Lab🔬 Simulator: Attribute Lookup Lab🔬 模拟器:属性查找实验室
Click lines to run them, in any order. Each store card shows its own __dict__ (shadows in orange) and what reading each name finds — from the object itself, or from the class. The coloured tags show which list or dict is the same object. The model was checked against real Python on 400 random sequences.
Lines पर click करके उन्हें किसी भी क्रम में चलाएँ। हर store card उसका अपना __dict__ (shadows नारंगी में) और हर नाम पढ़ने पर क्या मिलता है, दिखाता है — object से या class से। रंगीन tags बताते हैं कि कौन-सी list या dict एक ही object है। Model को 400 random sequences पर असली Python से जाँचा गया।
点击代码行即可运行,顺序随意。每张店铺卡片显示它 自己的 __dict__(遮蔽以橙色显示),以及 读取 每个名字时找到的值 — 来自对象本身还是来自类。彩色标签表示哪些列表或字典是同一个对象。该模型已在 400 个随机序列上与真实 Python 核对过。
Class Methods — Methods That Belong to the Class 🏛️Class Methods — Class के अपने Methods 🏛️类方法 — 属于类本身的方法 🏛️
A class method is a method whose first parameter is the class itself — named cls by convention — not an object. You mark it with the @classmethod decorator on the line above def. You usually call it on the class: CoffeeShop.from_csv(...).
Class method ऐसा method है जिसका पहला parameter ख़ुद class होती है — परंपरा से cls नाम — कोई object नहीं। इसे def के ऊपर वाली line पर @classmethod decorator से चिह्नित करते हैं। आमतौर पर इसे class पर बुलाते हैं: CoffeeShop.from_csv(...)।
类方法 的第一个参数是类本身 — 按惯例命名为 cls — 而不是对象。在 def 上一行加 @classmethod 装饰器来标记它。通常在类上调用它:CoffeeShop.from_csv(...)。
Three very common uses:
तीन बहुत आम इस्तेमाल:
三种非常常见的用途:
CoffeeShop.from_csv("Mumbai,8") splits a text row and returns a new store. The parsing stays with the class.CoffeeShop.from_csv("Mumbai,8") text row को तोड़कर नया store लौटाता है। Parsing class के साथ रहती है।CoffeeShop.from_csv("Mumbai,8") 拆分一行文本并返回一家新店。解析逻辑与类放在一起。CoffeeShop.update_price("latte", 5.00) raises the price for the whole chain.CoffeeShop.update_price("latte", 5.00) पूरी chain की price बढ़ाता है।CoffeeShop.update_price("latte", 5.00) 为整个连锁提价。CoffeeShop.how_many_open() returns the store count without needing any one store.CoffeeShop.how_many_open() किसी एक store के बिना store count लौटाता है।CoffeeShop.how_many_open() 不需要任何一家店就能返回门店数量。class CoffeeShop:
company_name = "Bean There"
menu = {"latte": 4.50, "espresso": 3.00}
total_stores = 0
def __init__(self, city, staff_count):
self.city = city
self.staff_count = staff_count
self.daily_revenue = 0.0
CoffeeShop.total_stores += 1
# -- Class method as an ALTERNATE CONSTRUCTOR --
@classmethod
def from_csv(cls, row: str):
"""Build a CoffeeShop from a CSV row like 'Mumbai,8'."""
city, staff = row.split(",")
return cls(city, int(staff)) # cls(...) is CoffeeShop(...) here
# -- Class method for a CLASS-WIDE OPERATION --
@classmethod
def update_price(cls, item, new_price):
"""HQ raises a price everywhere at once."""
cls.menu[item] = new_price
print(f"HQ: {item} is now ${new_price} at every store")
# -- Class method for an AGGREGATE QUERY --
@classmethod
def how_many_open(cls):
return cls.total_stores
mumbai = CoffeeShop("Mumbai", 8) # regular constructor
london = CoffeeShop.from_csv("London,12") # alternate constructor
tokyo = CoffeeShop.from_csv("Tokyo,20")
CoffeeShop.update_price("latte", 5.00) # class-wide operation
print(CoffeeShop.how_many_open()) # aggregate query
print(mumbai.menu["latte"]) # Mumbai sees the update
print(london.city, london.staff_count, type(london).__name__)
print(mumbai.how_many_open()) # also works through an object
The last line shows that a class method can also be called through an object. Python still passes the class as cls.
आख़िरी line दिखाती है कि class method को object के ज़रिए भी बुला सकते हैं। Python फिर भी cls के रूप में class ही भेजता है।
最后一行表明,类方法也可以通过对象调用。Python 仍然把 类 作为 cls 传入。
self answers "which object am I working on?". cls answers "which class am I working on?".
self बताता है "मैं किस object पर काम कर रहा हूँ?"। cls बताता है "मैं किस class पर काम कर रहा हूँ?"।
self 回答"我在处理哪个对象?";cls 回答"我在处理哪个类?"。
🎯 Simulator: Who Receives What?🎯 Simulator: किसे क्या मिलता है?🎯 模拟器:谁接收了什么?
Pick a call. The card that lands in the first parameter lights up with a self or cls badge, and the method's def line is highlighted. Each call starts from the same three stores and was recorded from a real Python run. (The PremiumCoffeeShop call is explained in Section 07.)
कोई call चुनें। पहले parameter में पहुँचने वाला card self या cls badge के साथ चमकता है, और method की def line हाइलाइट होती है। हर call उन्हीं तीन stores से शुरू होती है और असली Python run से रिकॉर्ड की गई। (PremiumCoffeeShop वाली call Section 07 में समझाई गई है।)
选一个调用。进入第一个参数的那张卡片会亮起 self 或 cls 标记,方法的 def 行也会高亮。每个调用都从同样的三家店开始,并由真实 Python 运行记录。(PremiumCoffeeShop 的调用在第 07 节解释。)
Why cls and Not Just CoffeeShop? 🧬cls क्यों, सीधे CoffeeShop क्यों नहीं? 🧬为什么用 cls 而不直接写 CoffeeShop?🧬
Inside a class method you could type the class name directly. But cls always means the class the method was actually called on. That matters when another class is built from this one (a subclass — a topic of its own, coming later). Here is the difference in one run:
Class method के अंदर आप class का नाम सीधे लिख सकते हैं। पर cls का मतलब हमेशा वह class है जिस पर method असल में बुलाया गया। यह तब मायने रखता है जब इस class से कोई दूसरी class बनाई जाए (subclass — यह अपना अलग topic है, आगे आएगा)। एक run में फ़र्क़ देखें:
在类方法里,你 可以 直接写类名。但 cls 永远表示方法 实际被调用 的那个类。当另一个类由这个类派生出来时(子类 — 这是单独的主题,以后会讲),这一点就很重要。看一次运行就明白了:
class CoffeeShop:
company_name = "Bean There"
def __init__(self, city, staff_count):
self.city = city
self.staff_count = staff_count
@classmethod
def from_csv(cls, row):
city, staff = row.split(",")
return cls(city, int(staff)) # uses cls, not CoffeeShop
class PremiumCoffeeShop(CoffeeShop): # a subclass
company_name = "Bean There Premium"
# Because from_csv uses cls, this returns a PremiumCoffeeShop
p = PremiumCoffeeShop.from_csv("Milan,10")
print(type(p).__name__)
print(p.company_name)
print(p.city, p.staff_count)
Now the same code with the class name typed in by hand:
अब वही code, class का नाम हाथ से लिखा हुआ:
再看同样的代码,但手动写死类名:
class CoffeeShop:
company_name = "Bean There"
def __init__(self, city, staff_count):
self.city = city
self.staff_count = staff_count
@classmethod
def from_csv(cls, row):
city, staff = row.split(",")
return CoffeeShop(city, int(staff)) # hard-coded class name
class PremiumCoffeeShop(CoffeeShop):
company_name = "Bean There Premium"
p = PremiumCoffeeShop.from_csv("Milan,10")
print(type(p).__name__) # the wrong type!
print(p.company_name)
Inside a @classmethod, always use cls — never the typed class name. It costs nothing and keeps your class working correctly with future subclasses.
@classmethod के अंदर हमेशा cls इस्तेमाल करें — कभी लिखा हुआ class नाम नहीं। इसमें कोई ख़र्च नहीं, और आपकी class आगे की subclasses के साथ सही चलती है।
在 @classmethod 里始终使用 cls — 不要写死类名。这毫无成本,还能让你的类与将来的子类正确配合。
Instance Method vs Class Method — At a Glance 👀Instance Method बनाम Class Method — एक नज़र में 👀实例方法与类方法 — 一览对比 👀
| Questionसवाल问题 | Instance methodInstance method实例方法 | Class methodClass method类方法 |
|---|---|---|
| Decorator needed?Decorator चाहिए?需要装饰器? | Noनहीं不需要 | @classmethod |
| First parameterपहला parameter第一个参数 | self — the objectself — objectself — 对象 | cls — the classcls — classcls — 类 |
| Called viaकैसे बुलाते हैं调用方式 | obj.method() | Class.method() (or obj.method())Class.method() (या obj.method())Class.method()(或 obj.method()) |
| Needs an existing object?मौजूदा object चाहिए?需要已有对象? | Yesहाँ需要 | Noनहीं不需要 |
| Read/write instance variables?Instance variables पढ़/लिख सकता है?能读写实例变量? | Yes — via self.xहाँ — self.x से能 — 通过 self.x | No — there is no selfनहीं — self नहीं है不能 — 没有 self |
| Read/write class variables?Class variables पढ़/लिख सकता है?能读写类变量? | Read yes; write through the class nameपढ़ना हाँ; लिखना class के नाम से可以读;写要通过类名 | Yes — via cls.xहाँ — cls.x से能 — 通过 cls.x |
| Creates new objects?नए objects बनाता है?创建新对象? | Rarely — not its jobकम ही — यह उसका काम नहीं很少 — 不是它的职责 | Often — return cls(...)अक्सर — return cls(...)经常 — return cls(...) |
| Typical useआम इस्तेमाल典型用途 | Behaviour of this one objectइसी एक object का व्यवहार这一个对象的行为 | Alternate constructor, class-wide change, aggregate queryAlternate constructor, पूरी class का बदलाव, aggregate query备用构造器、全类修改、汇总查询 |
Complete Practical Example — All Three Together ☕पूरा व्यावहारिक उदाहरण — तीनों एक साथ ☕完整实例 — 三者合一 ☕
One class that uses instance methods, class variables and class methods in a small, realistic example. Paste it, run it, and read it line by line.
एक class जो instance methods, class variables और class methods को एक छोटे, असली उदाहरण में इस्तेमाल करती है। Paste करें, चलाएँ, और line-by-line पढ़ें।
一个在小而真实的例子里同时使用实例方法、类变量和类方法的类。粘贴、运行,然后逐行阅读。
class CoffeeShop:
# == CLASS VARIABLES - shared across every store ==
company_name = "Bean There"
menu = {"latte": 4.50, "espresso": 3.00, "muffin": 3.50}
tax_rate = 0.10
total_stores = 0
def __init__(self, city, staff_count):
# == INSTANCE VARIABLES - one copy per store ==
self.city = city
self.staff_count = staff_count
self.daily_revenue = 0.0
self.orders = [] # a fresh list per store
CoffeeShop.total_stores += 1
# == INSTANCE METHOD - acts on THIS store ==
def serve(self, item):
if item not in CoffeeShop.menu:
raise ValueError(f"{item} not on menu")
price = CoffeeShop.menu[item] * (1 + CoffeeShop.tax_rate)
self.daily_revenue += price
self.orders.append(item)
print(f"[{self.city}] Served {item} for ${price:.2f}")
# == INSTANCE METHOD - reports THIS store's state ==
def report(self):
print(f"{self.city:8s} orders={len(self.orders):2d} "
f"revenue=${self.daily_revenue:7.2f}")
# == CLASS METHOD - alternate constructor ==
@classmethod
def from_csv(cls, row: str):
city, staff = row.split(",")
return cls(city.strip(), int(staff))
# == CLASS METHOD - HQ changes shared state ==
@classmethod
def update_price(cls, item, new_price):
cls.menu[item] = new_price
print(f"HQ: {item} is now ${new_price:.2f} everywhere")
# == CLASS METHOD - aggregate query ==
@classmethod
def chain_stats(cls):
return f"{cls.company_name}: {cls.total_stores} stores open"
# -- Open three stores - two ways --
mumbai = CoffeeShop("Mumbai", 8) # normal constructor
london = CoffeeShop.from_csv("London, 12") # class-method constructor
tokyo = CoffeeShop.from_csv("Tokyo, 20")
# -- Serve some drinks (instance methods on each store) --
mumbai.serve("latte")
mumbai.serve("muffin")
london.serve("espresso")
tokyo.serve("latte")
# -- HQ raises the latte price (class method -> class variable) --
CoffeeShop.update_price("latte", 5.00)
tokyo.serve("latte") # now costs $5.00 + tax
print()
for store in (mumbai, london, tokyo):
store.report()
print()
print(CoffeeShop.chain_stats())
The two empty lines in the output come from the two bare print() calls. Note the prices: 4.50 × 1.1 = 4.95, and after the price change 5.00 × 1.1 = 5.50.
Output की दो ख़ाली lines दो ख़ाली print() calls से आती हैं। Prices देखें: 4.50 × 1.1 = 4.95, और price बदलने के बाद 5.00 × 1.1 = 5.50।
输出中的两个空行来自两次空的 print() 调用。看看价格:4.50 × 1.1 = 4.95,调价后 5.00 × 1.1 = 5.50。
☕ Simulator: Run the Coffee Chain☕ Simulator: Coffee Chain चलाएँ☕ 模拟器:经营咖啡连锁
This is the class above, live. Serve drinks at any store, change a price at HQ, open a new store from a CSV row, then print the reports. Watch which card lights up: a store (self) or the class (cls). Every output line matches real Python — checked on 300 random sequences.
यह ऊपर वाली class है, live। किसी भी store पर drinks serve करें, HQ पर price बदलें, CSV row से नया store खोलें, फिर reports print करें। देखें कौन-सा card चमकता है: कोई store (self) या class (cls)। हर output line असली Python से मिलती है — 300 random sequences पर जाँची गई।
这就是上面那个类,实时运行。在任意门店出售饮品,在总部改价,用 CSV 行开新店,然后打印报告。留意哪张卡片亮起:某家店(self)还是类(cls)。每一行输出都与真实 Python 一致 — 已在 300 个随机序列上核对。
Every store served its own orders and kept its own revenue (instance methods, instance variables). They all read one shared menu and one shared tax rate (class variables). HQ raised the latte price with one call (a class method changing a class variable). Creating stores with from_csv and reporting with chain_stats ran on the class itself — no store needed.
हर store ने अपने orders serve किए और अपना revenue रखा (instance methods, instance variables)। सबने एक साझा menu और एक साझा tax rate पढ़ा (class variables)। HQ ने एक call से latte की price बढ़ाई (class method ने class variable बदला)। from_csv से stores बनाना और chain_stats से report करना ख़ुद class पर चला — किसी store की ज़रूरत नहीं।
每家店处理自己的订单、记录自己的营业额(实例方法、实例变量)。它们都读取同一份菜单和同一个税率(类变量)。总部一次调用就给拿铁提了价(类方法修改类变量)。用 from_csv 开店、用 chain_stats 汇总,都直接在类上运行 — 不需要任何门店。
When to Use Which — Decision Grid 🧭कब कौन-सा — Decision Grid 🧭何时用哪个 — 决策表 🧭
from_csv, from_dict, today(). The parsing stays where the class lives.from_csv, from_dict, today()। Parsing वहीं रहती है जहाँ class है।from_csv、from_dict、today()。解析逻辑留在类所在的地方。cls.something = new@classmethod because it "looks neater" takes away self.@classmethod लगाने से self छिन जाता है।@classmethod,会让你失去 self。self.total_stores = 99 makes a shadow, not an update. Write ClassName.total_stores = 99, or cls.total_stores inside a class method.self.total_stores = 99 update नहीं, shadow बनाता है। ClassName.total_stores = 99 लिखें, या class method के अंदर cls.total_stores।self.total_stores = 99 产生的是遮蔽,而不是更新。请写 ClassName.total_stores = 99,或在类方法里写 cls.total_stores。Common Mistakes (and Fixes) 🩹आम ग़लतियाँ (और उनके हल) 🩹常见错误(及修正)🩹
| Mistakeग़लती错误 | What goes wrongक्या बिगड़ता है会出什么问题 | Fixहल修正 |
|---|---|---|
Forgetting self in a methodMethod में self भूलना方法里忘写 self | TypeError: ... takes 0 positional arguments but 1 was given | Add self as the first parameterपहले parameter के रूप में self जोड़ें把 self 加为第一个参数 |
self.total = 99 to update a class variableClass variable बदलने के लिए self.total = 99用 self.total = 99 更新类变量 | Makes a shadow on that object — others unchangedउस object पर shadow बनता है — बाक़ी नहीं बदलते在该对象上产生遮蔽 — 其他对象不变 | ClassName.total = 99 |
Mutable class variable (orders = [])Mutable class variable (orders = [])可变类变量(orders = []) | Every object shares it — one .append() hits allहर object साझा करता है — एक .append() सब पर所有对象共享 — 一次 .append() 影响全部 | Create self.orders = [] in __init____init__ में self.orders = [] बनाएँ在 __init__ 中创建 self.orders = [] |
Forgetting @classmethod@classmethod भूलना忘写 @classmethod | It becomes a normal method — on the class, your first argument lands in clsयह सामान्य method बन जाता है — class पर, आपका पहला argument cls में चला जाता है它变成普通方法 — 在类上调用时,你的第一个参数落进 cls | Add @classmethod on the line aboveऊपर वाली line पर @classmethod जोड़ें在上一行加 @classmethod |
| Hard-coding the class name inside a class methodClass method में class का नाम hard-code करना在类方法里写死类名 | Subclasses get the wrong typeSubclasses को ग़लत type मिलता है子类得到错误的类型 | Use cls — that is why it is therecls इस्तेमाल करें — वह इसी लिए है使用 cls — 它就是为此存在的 |
Writing self.method without ()() के बिना self.method लिखना写 self.method 却漏了 () | You get the bound method object, not its resultनतीजे की जगह bound method object मिलता है得到的是绑定方法对象,而不是结果 | Add the parentheses: self.method()Parentheses जोड़ें: self.method()加上括号:self.method() |
A @classmethod that never uses clsऐसा @classmethod जो cls कभी इस्तेमाल न करे从不使用 cls 的 @classmethod | Probably the wrong toolशायद ग़लत tool可能用错了工具 | Use cls, or rethink it (@staticmethod is covered in a later tutorial)cls इस्तेमाल करें, या दोबारा सोचें (@staticmethod आगे के tutorial में)使用 cls,或重新考虑(@staticmethod 将在后续教程讲解) |
class Shop:
total = 0
def hello(): # forgot self
print("hi")
try:
Shop().hello()
except TypeError as e:
print("1. TypeError:", e)
class Shop2:
def __init__(self, city):
self.city = city
def from_csv(cls, row): # forgot @classmethod
return cls(row)
try:
Shop2.from_csv("Mumbai")
except TypeError as e:
print("2. TypeError:", e)
class Shop3:
def __init__(self, city):
self.city = city
def label(self):
return self.city.upper()
s = Shop3("Pune")
print("3.", s.label) # forgot the ()
print("3. fixed:", s.label())
🩺 Simulator: Bug Doctor🩺 Simulator: Bug Doctor🩺 模拟器:Bug 医生
Pick a mistake. The buggy version is on the left, the fixed one on the right, with the changed lines marked. Both outputs are real. Note that three of the six bugs give no error at all — they just quietly give wrong results.
कोई ग़लती चुनें। बाईं ओर buggy version है, दाईं ओर ठीक किया हुआ, बदली हुई lines चिह्नित। दोनों outputs असली हैं। ध्यान दें: छह में से तीन bugs कोई error नहीं देते — बस चुपचाप ग़लत नतीजे देते हैं।
选一个错误。左边是有 bug 的版本,右边是修正后的版本,改动的行已标出。两边的输出都是真实的。注意:六个 bug 中有三个 完全不报错 — 只是悄悄给出错误结果。
Quick Reference 📋Quick Reference 📋速查表 📋
| Taskकाम任务 | SyntaxSyntax语法 | Notesनोट说明 |
|---|---|---|
| Define an instance methodInstance method define करना定义实例方法 | def serve(self, item): | First parameter is always selfपहला parameter हमेशा self第一个参数永远是 self |
| Call an instance methodInstance method बुलाना调用实例方法 | store.serve("latte") | Python passes store as selfPython store को self बनाकर भेजता हैPython 把 store 作为 self 传入 |
| Read an instance variable insideअंदर instance variable पढ़ना在内部读取实例变量 | self.city | This object's own dataइसी object का अपना data这个对象自己的数据 |
| Declare a class variableClass variable declare करना声明类变量 | menu = {...} under the class lineclass line के नीचे menu = {...}在 class 行下写 menu = {...} | One copy, shared by every objectएक copy, हर object साझा करता है一份,所有对象共享 |
| Read a class variableClass variable पढ़ना读取类变量 | ClassName.menu or self.menuClassName.menu या self.menuClassName.menu 或 self.menu | Both work for readingपढ़ने के लिए दोनों चलते हैं读取时两者都可以 |
| Change a class variableClass variable बदलना修改类变量 | ClassName.total = ... or ClassName.menu["x"] = ...ClassName.total = ... या ClassName.menu["x"] = ...ClassName.total = ... 或 ClassName.menu["x"] = ... | Never self.total = ... (shadow)self.total = ... कभी नहीं (shadow)永远不要 self.total = ...(遮蔽) |
| Define a class methodClass method define करना定义类方法 | @classmethod + def m(cls, ...): | Decorator on the line above defDecorator def के ऊपर वाली line पर装饰器写在 def 上一行 |
| Alternate constructorAlternate constructor备用构造器 | return cls(...) | Use cls, not the class nameClass का नाम नहीं, cls用 cls,不要写类名 |
| Call a class methodClass method बुलाना调用类方法 | ClassName.from_csv("...") | No object neededObject की ज़रूरत नहीं不需要对象 |
| Count objectsObjects गिनना统计对象数 | Add to a class variable in __init____init__ में class variable बढ़ाएँ在 __init__ 里累加类变量 | ClassName.total += 1 |
self.menu = {...} (attribute assignment) makes a shadow. But self.menu["latte"] = 6.0 (item assignment) does not — it changes the shared dict that self.menu finds. It works, but it hides the fact that you are changing everyone's menu. Write CoffeeShop.menu[...] so the intent is clear. Try both in the Lookup Lab (Section 05).
self.menu = {...} (attribute assignment) shadow बनाता है। पर self.menu["latte"] = 6.0 (item assignment) नहीं बनाता — यह वह साझा dict बदलता है जो self.menu को मिलती है। यह चलता है, पर छिपा देता है कि आप सबका menu बदल रहे हैं। इरादा साफ़ रखने के लिए CoffeeShop.menu[...] लिखें। Lookup Lab (Section 05) में दोनों आज़माएँ।
self.menu = {...}(属性赋值)会产生遮蔽。但 self.menu["latte"] = 6.0(元素赋值)不会 — 它修改的是 self.menu 找到的共享字典。这样能运行,但掩盖了你在修改 所有人 菜单的事实。写成 CoffeeShop.menu[...] 意图才清楚。可以在查找实验室(第 05 节)里试试两者。
Golden Rules and Quiz 🏆सुनहरे नियम और Quiz 🏆黄金法则与小测验 🏆
self = one object, cls = the class itself.self = एक object, cls = ख़ुद class।self = 一个对象,cls = 类本身。@classmethod only when you do not need self — usually an alternate constructor, a class-wide change, or an aggregate query.@classmethod तभी लें जब self की ज़रूरत न हो — आमतौर पर alternate constructor, पूरी class का बदलाव, या aggregate query।self 时才用 @classmethod — 通常是备用构造器、全类修改或汇总查询。__init__.__init__ में रखें।__init__。__init__ as self.x = [].__init__ में self.x = [] के रूप में रहती है।__init__ 中写成 self.x = []。CoffeeShop.total_stores += 1, never self.total_stores += 1. The self form quietly makes a shadow and leaves the class variable unchanged.CoffeeShop.total_stores += 1, कभी self.total_stores += 1 नहीं। self वाला रूप चुपचाप shadow बनाता है और class variable को नहीं बदलता।CoffeeShop.total_stores += 1,绝不要 self.total_stores += 1。self 写法会悄悄产生遮蔽,类变量保持不变。@classmethod on the line above def, and name the first parameter cls. Without the decorator the method breaks (the first argument lands in the wrong place). cls is only a convention, but every Python programmer expects it.def के ऊपर वाली line पर @classmethod रखें, और पहले parameter का नाम cls रखें। Decorator के बिना method टूट जाता है (पहला argument ग़लत जगह पहुँचता है)। cls सिर्फ़ परंपरा है, पर हर Python programmer यही उम्मीद करता है।@classmethod 写在 def 上一行,并把第一个参数命名为 cls。 没有装饰器,方法就会出错(第一个参数落到错误的位置)。cls 只是约定,但每个 Python 程序员都期待这样写。cls(...), not ClassName(...). It keeps subclasses working — at no cost.cls(...) से बनाएँ, ClassName(...) से नहीं। इससे subclasses सही चलती हैं — बिना किसी ख़र्च के।cls(...) 创建对象,而不是 ClassName(...)。这样子类也能正确工作 — 零成本。Employee.from_csv, date.today()) over helper functions outside the class. They keep the building logic next to the type they build.Employee.from_csv, date.today()), class के बाहर के helper functions की जगह। ये बनाने का logic उसी type के पास रखते हैं।Employee.from_csv、date.today()),而不是类外的辅助函数。它们让构建逻辑紧挨着所构建的类型。store.company_name is fine for reading — Python falls back to the class. The moment you write store.company_name = "...", you have made a per-object attribute.store.company_name ठीक है — Python class तक जाता है। जैसे ही आप store.company_name = "..." लिखते हैं, आपने हर-object वाला attribute बना दिया।store.company_name 没问题 — Python 会退回到类上找。一旦你写 store.company_name = "...",就创建了一个对象自己的属性。Quick Quiz — 8 Questionsछोटा Quiz — 8 सवाल小测验 — 8 道题
Instance methods get self and work on one object's data. Class variables live once on the class; reading through an object falls back to them, but writing through an object makes a shadow. Class methods get cls and work on the class — to build objects with cls(...), change shared data, or answer questions about all objects.
Instance methods को self मिलता है और वे एक object के data पर काम करते हैं। Class variables class पर एक बार रहते हैं; object के ज़रिए पढ़ने पर Python उन तक जाता है, पर object के ज़रिए लिखने से shadow बनता है। Class methods को cls मिलता है और वे class पर काम करते हैं — cls(...) से objects बनाने, साझा data बदलने, या सभी objects के बारे में सवालों के जवाब देने के लिए।
实例方法接收 self,处理某一个对象的数据。类变量在类上只存一份;通过对象读取会回退到它们,但通过对象写入会产生遮蔽。类方法接收 cls,作用于类本身 — 用 cls(...) 创建对象、修改共享数据,或回答关于所有对象的问题。