为什么我们更喜欢使用self.method()而不是Class.method(self)

时间:2021-05-03 22:28:11

For example, for some class:

例如,对于某些类:

class Class(object):
    def __init__(self):
        pass

    def something(self):    # yes I know this could be static
        print("something")

and instance

和实例

instance = Class()

the following are both technically valid:

以下两者在技术上都是有效的:

instance.something()       # normal
Class.something(instance)  # but also technically valid

Is there some explicit reasoning why the first use case is preferred? I can think of examples like iterating over instances and calling methods, but I can also think of some cases where it may be easier to interpret my code when explicit reference to the Class I am using is visible.

是否有一些明确的推理为什么首选用例是首选?我可以想到迭代实例和调用方法等示例,但我也可以想到一些情况,当我明确引用我正在使用的类时,可能更容易解释我的代码。

Apologies if this has been answered before. I could not find it, which may be due to my difficulty in phrasing the question.

如果之前已经回答过,请道歉。我找不到它,这可能是由于我在措辞问题上的困难。

1 个解决方案

#1


7  

Class.something(instance) grabs the method from a specific class. self.something() uses the class for that instance, and that is not necessarily the same class.

Class.something(instance)从特定类中获取方法。 self.something()使用该实例的类,并且不一定是同一个类。

You also repeat yourself a lot if you have to keep using the class name.

如果你必须继续使用类名,你也会重复很多。

Your title uses self, which indicates code inside a method. Compare the output of the following examples:

您的标题使用self,表示方法中的代码。比较以下示例的输出:

class Animal:
    def make_sound(self):
        print('General nature sounds')

    def startle(self):
        self.make_sound()

    def pet(self):
        Animal.make_sound(self)

class Dog(Animal):
    def make_sound(self):
        # overrides Animal.make_sound()
        print('Bark!')

dog = Dog()
dog.startle()  # prints "Bark!"
dog.pet()      # prints "General nature sounds"

Animal.make_sound(self) works, but will use the original method, ignoring the new implementation for Dog.make_sound().

Animal.make_sound(self)有效,但会使用原始方法,忽略Dog.make_sound()的新实现。

For the case where you have a reference to an instance somewhere else, consider the case where you accept a class or a subclass:

对于您在其他地方引用实例的情况,请考虑接受类或子类的情况:

class Cat(Animal):
    def make_sound(self):
        print('Meouw!')

def groom_pet(pet):
    pet.startle()
    Animal.make_sound(pet)

groom_pet(Cat())  # prints "Meouw", then "General nature sounds"

So we have a new subclass of Animal, and groom_pet() can accept any Animal instance, because subclasses will also have the same methods. But pet.startle() will end up calling the right make_sound() implementation, while Animal.make_sound() will again bypass the correct implementation.

所以我们有一个新的Animal子类,而groom_pet()可以接受任何Animal实例,因为子类也有相同的方法。但是pet.startle()将最终调用正确的make_sound()实现,而Animal.make_sound()将再次绕过正确的实现。

Very rarely should you use the unbound class method over the bound method on an instance. There are reasons to use this sometimes; specifically if you want to bypass a parent class method (so not using super().method()), or if you want to improve performance and avoid looking up an attribute and binding the method in a tight loop.

很少应该在实例上对绑定方法使用未绑定的类方法。有时候有理由使用它;特别是如果你想绕过父类方法(所以不使用super()。method()),或者你想提高性能并避免查找属性并在紧密循环中绑定方法。

Because such cases are rare and special, you want to stick to the normal idiom, because that aids understanding of your code for both yourself and other readers. Don't surprise those readers.

因为这种情况很少见且很特殊,所以你要坚持使用正常的习语,因为这有助于你自己和其他读者理解你的代码。不要让那些读者感到惊讶。

#1


7  

Class.something(instance) grabs the method from a specific class. self.something() uses the class for that instance, and that is not necessarily the same class.

Class.something(instance)从特定类中获取方法。 self.something()使用该实例的类,并且不一定是同一个类。

You also repeat yourself a lot if you have to keep using the class name.

如果你必须继续使用类名,你也会重复很多。

Your title uses self, which indicates code inside a method. Compare the output of the following examples:

您的标题使用self,表示方法中的代码。比较以下示例的输出:

class Animal:
    def make_sound(self):
        print('General nature sounds')

    def startle(self):
        self.make_sound()

    def pet(self):
        Animal.make_sound(self)

class Dog(Animal):
    def make_sound(self):
        # overrides Animal.make_sound()
        print('Bark!')

dog = Dog()
dog.startle()  # prints "Bark!"
dog.pet()      # prints "General nature sounds"

Animal.make_sound(self) works, but will use the original method, ignoring the new implementation for Dog.make_sound().

Animal.make_sound(self)有效,但会使用原始方法,忽略Dog.make_sound()的新实现。

For the case where you have a reference to an instance somewhere else, consider the case where you accept a class or a subclass:

对于您在其他地方引用实例的情况,请考虑接受类或子类的情况:

class Cat(Animal):
    def make_sound(self):
        print('Meouw!')

def groom_pet(pet):
    pet.startle()
    Animal.make_sound(pet)

groom_pet(Cat())  # prints "Meouw", then "General nature sounds"

So we have a new subclass of Animal, and groom_pet() can accept any Animal instance, because subclasses will also have the same methods. But pet.startle() will end up calling the right make_sound() implementation, while Animal.make_sound() will again bypass the correct implementation.

所以我们有一个新的Animal子类,而groom_pet()可以接受任何Animal实例,因为子类也有相同的方法。但是pet.startle()将最终调用正确的make_sound()实现,而Animal.make_sound()将再次绕过正确的实现。

Very rarely should you use the unbound class method over the bound method on an instance. There are reasons to use this sometimes; specifically if you want to bypass a parent class method (so not using super().method()), or if you want to improve performance and avoid looking up an attribute and binding the method in a tight loop.

很少应该在实例上对绑定方法使用未绑定的类方法。有时候有理由使用它;特别是如果你想绕过父类方法(所以不使用super()。method()),或者你想提高性能并避免查找属性并在紧密循环中绑定方法。

Because such cases are rare and special, you want to stick to the normal idiom, because that aids understanding of your code for both yourself and other readers. Don't surprise those readers.

因为这种情况很少见且很特殊,所以你要坚持使用正常的习语,因为这有助于你自己和其他读者理解你的代码。不要让那些读者感到惊讶。