Object Oriented Python 简明教程

Object Oriented Python - Advanced Features

在此,我们将研究 Python 提供的部分高级特性

Core Syntax in our Class design

在此,我们将关注 Python 如何让我们利用我们的类中的操作符。Python 主要涉及对象和方法在对象上的调用,即使它隐藏在某种便捷的语法中时也是如此。

>>> var1 = 'Hello'
>>> var2 = ' World!'
>>> var1 + var2
'Hello World!'
>>>
>>> var1.__add__(var2)
'Hello World!'
>>> num1 = 45
>>> num2 = 60
>>> num1.__add__(num2)
105
>>> var3 = ['a', 'b']
>>> var4 = ['hello', ' John']
>>> var3.__add__(var4)
['a', 'b', 'hello', ' John']

因此,如果我们需要将魔术方法 add 添加到我们自己的类,我们可以这样做吗。让我们尝试。

我们有一个名为 Sumlist 的类,它具有一个构造函数 init ,该构造函数获取一个列表作为名为 my_list 的参数。

class SumList(object):
   def __init__(self, my_list):
      self.mylist = my_list
   def __add__(self, other):
     new_list = [ x + y for x, y in zip(self.mylist, other.mylist)]

     return SumList(new_list)

   def __repr__(self):
      return str(self.mylist)

aa = SumList([3,6, 9, 12, 15])

bb = SumList([100, 200, 300, 400, 500])
cc = aa + bb # aa.__add__(bb)
print(cc) # should gives us a list ([103, 206, 309, 412, 515])

Output

[103, 206, 309, 412, 515]

但有很多方法是由其他魔术方法内部管理的。以下列出部分方法,

'abc' in var # var.__contains__('abc')
var == 'abc' # var.__eq__('abc')
var[1] # var.__getitem__(1)
var[1:3] # var.__getslice__(1, 3)
len(var) # var.__len__()
print(var) # var.__repr__()

Inheriting From built-in types

类还可从内置类型继承,这意味着从任何内置类型继承并利用在其中发现的所有功能。

在以下示例中,我们正在从字典继承,但我们正在实现它的一种方法 setitem 。在我们设置字典中的键值时,会调用此 (setitem) 方法。由于这是一个魔术方法,因此它将隐式调用。

class MyDict(dict):

   def __setitem__(self, key, val):
      print('setting a key and value!')
      dict.__setitem__(self, key, val)

dd = MyDict()
dd['a'] = 10
dd['b'] = 20

for key in dd.keys():
   print('{0} = {1}'.format(key, dd[key]))

Output

setting a key and value!
setting a key and value!
a = 10
b = 20

让我们扩展我们的前一个示例,以下我们调用了两个魔术方法 getitemsetitem ,在处理列表索引时会更好用。

# Mylist inherits from 'list' object but indexes from 1 instead for 0!
class Mylist(list): # inherits from list
   def __getitem__(self, index):
      if index == 0:
         raise IndexError
      if index > 0:
         index = index - 1
         return list.__getitem__(self, index) # this method is called when

# we access a value with subscript like x[1]
   def __setitem__(self, index, value):
      if index == 0:
         raise IndexError
      if index > 0:
      index = index - 1
      list.__setitem__(self, index, value)

x = Mylist(['a', 'b', 'c']) # __init__() inherited from builtin list

print(x) # __repr__() inherited from builtin list

x.append('HELLO'); # append() inherited from builtin list

print(x[1]) # 'a' (Mylist.__getitem__ cutomizes list superclass
               # method. index is 1, but reflects 0!

print (x[4]) # 'HELLO' (index is 4 but reflects 3!

Output

['a', 'b', 'c']
a
HELLO

在上面的示例中,我们在 Mylist 中设置了一个三项列表,并隐式调用 init 方法,并且在我们打印元素 x 时,我们获得了三项列表 ([‘a’,’b’,’c’])。然后,我们将另一元素附加到该列表。稍后我们询问索引 1 和索引 4。但如果你查看输出,我们正在从 (index-1) 中获取我们所要求的元素。众所周知,列表索引从 0 开始,但这里的索引从 1 开始(这就是我们获取列表中第一个项的原因)。

Naming Conventions

在此,我们将研究我们对变量(特别是私有变量)使用的名称以及全世界 Python 程序员使用的约定。尽管变量被指定为私有的,但 Python 中没有隐私,这是设计使然。与任何其他有据可查的语言一样,Python 也有命令和风格方面的惯例,虽然它并不强制执行它们,但会推广它们。有一个由 Guido van Rossum” the originator of Python, that describe the best practices and use of name and is called PEP8. Here is the link for this, https://www.python.org/dev/peps/pep-0008/ 编写的风格指南

PEP 代表 Python 增强提案,是一系列文档,在 Python 社区中分发,以讨论提议的更改。例如,建议所有人,

  1. Module names − all_lower_case

  2. 类名和异常名 - 驼峰式

  3. 全局名称和局部名称 - 全小写

  4. 函数和方法名称 - 全小写

  5. Constants − ALL_UPPER_CASE

这些只是建议,如果你愿意,可以随时更改。但由于大多数开发人员都遵循这些建议,因此你的代码的可读性可能会降低。

Why conform to convention?

我们可以遵循 PEP 建议,因为这允许我们获得,

  1. 更多开发人员熟悉

  2. 代码的大多数读者都更清楚。

  3. 与处理相同代码库的其他贡献者的风格相匹配。

  4. 专业软件开发人员的标志

  5. Everyone will accept you.

Variable Naming − ‘Public’ and ‘Private’

在 Python 中,当我们处理模块和类时,我们将一些变量或属性指定为私有。在 Python 中,不存在“私有”实例变量,除了对象内部以外,无法访问该变量。私有简单地意味着它们根本不是供代码用户使用,而是供内部使用。通常,大多数 Python 开发人员遵循一个惯例,即一个名称以下划线开头,例如。 _attrval(以下示例)应被视为 API 或任何 Python 代码的非公有部分,无论它是一个函数、一个方法还是一个数据成员。以下是我们遵循的命名约定,

  1. 公有属性或变量(供此模块的导入者或此类的用户使用)− regular_lower_case

  2. 私有属性或变量(模块或类的内部使用)− _single_leading_underscore

  3. 不应子类化的私有属性 − __double_leading_underscore

  4. Magic 属性 − double_underscores (使用它们,不要创建它们)

class GetSet(object):

   instance_count = 0 # public

   __mangled_name = 'no privacy!' # special variable

   def __init__(self, value):
      self._attrval = value # _attrval is for internal use only
      GetSet.instance_count += 1

   @property
   def var(self):
      print('Getting the "var" attribute')
      return self._attrval

   @var.setter
   def var(self, value):
      print('setting the "var" attribute')
      self._attrval = value

   @var.deleter
   def var(self):
      print('deleting the "var" attribute')
      self._attrval = None

cc = GetSet(5)
cc.var = 10 # public name
print(cc._attrval)
print(cc._GetSet__mangled_name)

Output

setting the "var" attribute
10
no privacy!