类是 Python 的核心。它们给了我们很大的力量,但很容易滥用这种力量。在本节中,我将分享一些与 Python 中的类相关的模糊技巧和警告。我们开始吧!

实例和类变量

大多数初学者甚至一些高级 Python 程序员都不理解实例和类变量之间的区别。他们缺乏理解迫使他们错误地使用这些不同类型的变量。让我们理解他们。

基本区别是:

  • 实例变量用于每个对象都是唯一的数据。
  • 类变量用于在类的不同实例之间共享的数据。

我们来看一个例子:

  1. class Cal(object):
  2. # pi 是类变量
  3. pi = 3.142
  4. def __init__(self, radius):
  5. # self.radius 是实例变量
  6. self.radius = radius
  7. def area(self):
  8. return self.pi * (self.radius ** 2)
  9. a = Cal(32)
  10. a.area()
  11. # Output: 3217.408
  12. a.pi
  13. # Output: 3.142
  14. a.pi = 43
  15. a.pi
  16. # Output: 43
  17. b = Cal(44)
  18. b.area()
  19. # Output: 6082.912
  20. b.pi
  21. # Output: 3.142
  22. b.pi = 50
  23. b.pi
  24. # Output: 50

使用不可变类变量时没有太多问题。因为一切正常,初学者不会尝试更多地了解这个主题,这是主要原因! 如果你还认为如果使用不正确,实例和类变量不会导致任何问题,看看下一个示例。

  1. class SuperClass(object):
  2. superpowers = []
  3. def __init__(self, name):
  4. self.name = name
  5. def add_superpower(self, power):
  6. self.superpowers.append(power)
  7. foo = SuperClass('foo')
  8. bar = SuperClass('bar')
  9. foo.name
  10. # Output: 'foo'
  11. bar.name
  12. # Output: 'bar'
  13. foo.add_superpower('fly')
  14. bar.superpowers
  15. # Output: ['fly']
  16. foo.superpowers
  17. # Output: ['fly']

这是可变类变量错误使用的美妙之处。为了使你的代码安全抵御这种意外攻击,请确保你不使用可变类变量。 只有当你知道自己在做什么时,才可以使用它们。

新样式的类

Python 2.1 中引入了新的样式类,但是现在很多人都不知道它们!之所以如此,是因为 Python 还支持 旧样式类以保持向后兼容性。我已经说了很多关于新旧的事情,但我没有告诉你这个差异。那么主要区别在于:

  • 旧的基类不会从任何东西继承。
  • 新样式基类继承自 object

一个非常基本的例子是:

  1. class OldClass():
  2. def __init__(self):
  3. print('I am an old class')
  4. class NewClass(object):
  5. def __init__(self):
  6. print('I am a jazzy new class')
  7. old = OldClass()
  8. # Output: I am an old class
  9. new = NewClass()
  10. # Output: I am a jazzy new class

object 继承允许新样式类利用一些 魔法。 一个主要优点是您可以使用一些有用的优化,如 __slots__。 您可以使用 super() 和描述符等。 底线?总是尝试使用新式的类。

注意:Python 3 只有新式的类。无论您是否从 object 继承,都无关紧要。但是,建议您仍然从 object 继承。

魔术方法

Python 的类以其神奇的方法而闻名,通常称为 dunder(双下划线)方法。我将讨论其中的一些。

  • __init__

它是一个类初始化器。 每当创建一个类的实例时,都会调用其 __init__ 方法。 例如:

  1. class GetTest(object):
  2. def __init__(self):
  3. print('Greetings!!')
  4. def another_method(self):
  5. print('I am another method which is not'
  6. ' automatically called')
  7. a = GetTest()
  8. # Output: Greetings!!
  9. a.another_method()
  10. # Output: I am another method which is not automatically
  11. # called

你可以看到在实例在创建后会立即调用 __init__。 你还可以在初始化期间将参数传递给类。像这样:

  1. class GetTest(object):
  2. def __init__(self, name):
  3. print('Greetings!! {0}'.format(name))
  4. def another_method(self):
  5. print('I am another method which is not'
  6. ' automatically called')
  7. a = GetTest('yasoob')
  8. # Output: Greetings!! yasoob
  9. # Try creating an instance without the name arguments
  10. b = GetTest()
  11. Traceback (most recent call last):
  12. File "<stdin>", line 1, in <module>
  13. TypeError: __init__() takes exactly 2 arguments (1 given)

我相信你现在了解了 __init__ 方法。

  • __getitem__

在类中实现 getitem 允许其实例使用 [](索引器)运算符。这是一个例子:

  1. class GetTest(object):
  2. def __init__(self):
  3. self.info = {
  4. 'name':'Yasoob',
  5. 'country':'Pakistan',
  6. 'number':12345812
  7. }
  8. def __getitem__(self,i):
  9. return self.info[i]
  10. foo = GetTest()
  11. foo['name']
  12. # Output: 'Yasoob'
  13. foo['number']
  14. # Output: 12345812

如果没有 __getitem__方法,我们会遇到以下错误:

  1. >>> foo['name']
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. TypeError: 'GetTest' object has no attribute '__getitem__'