self、cls、@staticmethod和@classmethod的区别
1. self vs C# 的 this
class Dog:
def __init__(self, name):
self.name = name # self 代表"哪只狗"
def bark(self): # 普通方法,第一个参数是 self
print(f"{self.name}: 汪汪!")
a = Dog("旺财")
b = Dog("小白")
a.bark() # 旺财: 汪汪! ← self 就是 a
b.bark() # 小白: 汪汪! ← self 就是 bclass Dog
{
public string Name;
public Dog(string name)
{
this.Name = name; // this 代表"哪只狗"
}
public void Bark()
{
Console.WriteLine($"{this.Name}: 汪汪!");
}
}
var a = new Dog("旺财");
var b = new Dog("小白");
a.Bark(); // 旺财: 汪汪! ← this 就是 a
b.Bark(); // 小白: 汪汪! ← this 就是 b💡 Python 的 self 必须写在方法参数里,C# 的 this 是隐式的。
2. @classmethod 和 cls
class Dog:
def __init__(self, name):
self.name = name # self 代表"哪只狗"
def bark(self): # 普通方法,第一个参数是 self
print(f"{self.name}: 汪汪!")
a = Dog("旺财")
b = Dog("小白")
a.bark() # 旺财: 汪汪! ← self 就是 a
b.bark() # 小白: 汪汪! ← self 就是 bclass Dog
{
public static string Species = "犬科"; // 静态字段,所有狗共享
public string Name; // 实例字段,每只狗不同
public static string GetSpecies() // C# 的 static 方法 ≈ Python 的 @classmethod
{
return $"我们都是{Species}";
}
}
Console.WriteLine(Dog.GetSpecies()); // 我们都是犬科💡 C# 里没有 cls 的概念,用 static 方法 + 类名访问静态成员来实现类似效果。
3. @classmethod 的工厂方法(子类继承时 cls 的妙处)
class Animal:
@classmethod
def create(cls, name):
return cls(name) # cls 会自动变成调用它的那个类
class Dog(Animal):
pass
class Cat(Animal):
pass
dog = Dog.create("旺财") # cls = Dog,返回 Dog 实例
cat = Cat.create("咪咪") # cls = Cat,返回 Cat 实例
print(type(dog)) # <class 'Dog'> ✅
print(type(cat)) # <class 'Cat'> ✅class Animal
{
public string Name;
public Animal(string name)
{
Name = name;
}
// C# 没有 cls,但可以用泛型实现类似效果
public static T Create<T>(string name) where T : Animal
{
return (T)Activator.CreateInstance(typeof(T), name);
}
}
class Dog : Animal { public Dog(string name) : base(name) { } }
class Cat : Animal { public Cat(string name) : base(name) { } }
var dog = Animal.Create<Dog>("旺财"); // 返回 Dog 实例
var cat = Animal.Create<Cat>("咪咪"); // 返回 Cat 实例
Console.WriteLine(dog.GetType()); // Dog ✅
Console.WriteLine(cat.GetType()); // Cat ✅4. @staticmethod vs C# 的 static
class Calculator:
@staticmethod
def add(a, b): # 没有 self,也没有 cls
return a + b
# 直接用类名调用,不需要实例
result = Calculator.add(1, 2) # 3class Calculator
{
public static int Add(int a, int b) // 没有 this
{
return a + b;
}
}
// 直接用类名调用,不需要实例
int result = Calculator.Add(1, 2); // 3💡 C# 的 static 和 Python 的 @staticmethod 几乎一模一样。
5. 三者对比
class Demo:
class_var = "我是类变量"
def __init__(self):
self.instance_var = "我是实例变量"
def normal_method(self):
# 能访问:self(实例)、类
print("普通方法", self.instance_var)
@classmethod
def class_method(cls):
# 能访问:cls(类)、类变量
# 不能访问:self(实例变量)
print("类方法", cls.class_var)
@staticmethod
def static_method():
# 不能访问:self、cls
# 就是个普通函数,放在类里只是为了组织代码
print("静态方法")class Demo
{
public static string ClassVar = "我是类变量";
public string InstanceVar = "我是实例变量";
public void NormalMethod() // 普通方法 ≈ Python 的 self
{
Console.WriteLine($"普通方法 {InstanceVar}");
}
public static void ClassMethod() // 静态方法 ≈ Python 的 @classmethod
{
Console.WriteLine($"类方法 {ClassVar}");
// 不能访问 InstanceVar(需要实例)
}
public static void StaticMethod() // 静态方法 ≈ Python 的 @staticmethod
{
Console.WriteLine("静态方法");
}
}@staticmethod和@classmethod的区别总结
@staticmethod:
UserResponse.success()
↓
代码里写的是 Response()
↓
永远返回 Response ← 不管谁调用,结果一样
@classmethod:
UserResponse.success()
↓
cls 自动变成 UserResponse
↓
返回 UserResponse ← 谁调用就返回谁的类型
@staticmethod → 永远用父类(写死了)
@classmethod → 用当前调用它的子类本身(自动适配)
就这一个区别,记住就够了。👍
评论