在这里我们来看看Python提供的一些高级功能。
类设计中的核心语法
在此将着眼于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__
,它将list
作为名为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])
执行上面示例代码,得到以下结果 -
[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__()
继承自内置的类型
类还可以从内置类型继承,这意味着从任何内置继承,并利用其中找到的所有功能。
在下面的例子中,从字典继承,并实现它的一个方法__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]))
执行上面示例代码,得到以下结果 -
setting a key and value!
setting a key and value!
a = 10
b = 20
继续前面的例子,下面在处理列表索引时调用了两个名为__getitem__
和__setitem__
的魔术方法。
# 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!
执行上面示例代码,得到以下结果 -
['a', 'b', 'c']
a
HELLO
在上面的例子中,在Mylist中设置了三个项目列表,并隐式调用__init__
方法,当打印元素x
时,我们得到三个项目列表(['a','b','c'])
。 然后在这个列表中追加另一个元素。 后来打印索引1
和索引4
。如果看到从(索引-1)中获得所要求的元素。 我们知道,列表索引从0
开始,但这里索引从1
开始(这就是为什么要得到是列表的第一项)。
命名约定
在这里,我们将查看用于变量的名称,特别是全局Python程序员使用的私有变量和约定。 尽管变量被指定为私有,但在Python中并没有隐私,并且这是按设计的。 和任何其他有良好记录的语言一样,Python具有它提出的命名和样式约定,尽管它没有强制执行它们。 有一个由“Guido van Rossum”编写的Python风格指南,它描述了最佳实践和名称的使用,被称为PEP8。 这里是这个链接,https://www.python.org/dev/peps/pep-0008/
PEP代表Python增强提议,并且是一系列在Python社区中分发以讨论提议的更改的文档。 例如,建议所有人,
- 模块名称 - all_lower_case
- 类名称和异常名称 - CamelCase
- 全局和本地名称 - all_lower_case
- 函数和方法名称 - all_lower_case
- 常量 - ALL_UPPER_CASE
这些只是推荐,如果你喜欢,可以根据需要改变。 但是,由于大多数开发人员遵循这些建议,那么可能代码很容易阅读。
为什么遵守惯例?
可以遵循允许获得的PEP建议,
- 对绝大多数开发人员更熟悉。
- 大多数读者更阅读代码。
- 将匹配在相同代码库上工作的其他贡献者的风格。
- 注解是一名专业软件开发人员必要的工作。
- 每个人都会接受。
变量命名 - ‘公共’和’私人’
在Python中,当处理模块和类时,将一些变量或属性指定为私有。 在Python中,除了在对象内部之外,不存在“私有”实例变量。 私有仅仅意味着它们根本不打算被代码的用户使用,而是打算在内部使用。 一般来说,大多数Python开发人员都遵循一个约定,例如,名称前面加上一个下划线。_attrval
(下面的示例)应该被视为API或任何Python代码的非公开部分,无论它是函数,方法还是数据成员。 以下是遵循的命名约定,
- 公共属性或变量(打算由此模块的导入者或此类的用户使用)-
regular_lower_case
- 私有属性或变量(由模块或类内部使用)-
_single_leading_underscore
- 不应被子类化的私有属性 -
__ double_leading_underscore
- 魔术属性 -
__ 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)
执行上面示例代码,得到以下结果 -
setting the "var" attribute
10
no privacy!