パイソン学習の第12回講義
一、特殊方法
- 在类中可以定义一些特殊特殊方法
- 完成特殊方法需要保证的三点
- 1.在类中,name对我我们的程序是必须的
- 2.但是,name又都是不同的
- 3.在设置好name之后手动添加属性又融基忘记
- 完成特殊方法需要保证的三点
- 特殊方法的形式
- 语法:
__名称__()
这种方式的方法就是特殊方法,又称为魔法方法。
- 特殊方法不需要我们调用,特殊方法会在特定的时间自动调用。
- 特殊方法演示示例:
1.普通的类:
class Person:
# 在类的内部创建一个方法(speak是方法名)
def speak(self):
print('你好我是%s' % self.name)
# 创建对象(实例)
p1 = Person()
p1.name = '刘德华'
p2 = Person()
p2.name = '张家辉'
p1.speak()
p2.speak()
打印输出结果:
你好我是刘德华
你好我是张家辉
2.特殊方法类:
class Person:
# 类属性:
# name = '向华强'
def __init__(self,name): # 新建init方法 # self就是实例(对象),通过类似函数穿参的模式,将name传入实参
self.name = name
# print('类中的print') # 通过总结2可知,本行代码如果运行,将是最先运行的代码。
def speak(self): # 新建speak方法
print('大家好,我是%s' % self.name)
p1 = Person('刘德华') # 本行代码中的刘德华,就像函数穿参的中的实参。通过函数函数穿参的模式,传递给33行代码中的name,函数再继续向下执行,通过38行代码进行拼接,打印输出。
# 调用init方法
# p1.__init__() # 通过总结1可知本行代码属于二次调用,非需要时,不写。
p2 = Person('郭富城')
p3 = Person('何润东')
p1.speak()
p2.speak()
p3.speak()
打印输出结果:
大家好,我是刘德华
大家好,我是郭富城
大家好,我是何润东
总结:
- 1.每创建一个实例对象,解释器python就会调用一次init魔法方法。
- 2.在面向对象的函数中,类是最大的,执行顺序也是优先执行的。
二、封装的引入
- 封装的基本概念
- 封装是面向对象的三大特征之一。
- 封装出现的原因:
- 1.属性不能随意修改
- 2.属性不能改为任意的值
- 封装是指隐藏对象中一些不希望被外部所访问的属性和方法。
- 我们可以提供一个getter()方法和setter()方法是外部可以访问已经封装的属性。
- getter()方法用来获取对象中指定的属性
- setter()方法用来设置对象指定的属性
- 封装的思想:
- 1.我们需要一种方式来增强数据的安全性。
- 2.属性不能随意更改。(允许修改时,才能修改。)
- 3.属性不能为任意值。
- 可以为对象的属性使用双下划线开头
__xxx
。双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问。 - 其实隐藏属性只不过是python自动为属性改了一个名字——>
_累名__属性名
,例如__name ——>_Person__name
(这种方式实际上依然可以在外部访问,但是这种方式我们一般不用。一般我们会将一些私有属性以单下划线开头) - 一般来说,单下划线开头的属性都是私有实行,没有特殊情况下不要修改私有属性。
封装思想的简单演示:
class Car:
def __init__(self, name, color):
self.name = name
self.color = color
def run(self):
print('汽车开始跑了')
def horn(self):
print('BIBIBIBIKBI')
car = Car('法拉利','红色')
# print(car.name, car.color)
car.name = '小猫咪'
print(car.name,car.color)
car.run()
car.horn()
打印输出结果:
汽车开始跑了
BIBIBIBIKBI
分析:上述代码应该输出
小猫咪 红色
汽车开始跑了
BIBIBIBIKBI
但是为car实例添加的属性为小猫咪时,小猫咪的这恶搞属性就覆盖了法拉利。
这样就打乱了这一类的代码。导致错误。
三、封装
- 封装其实是做出一个相对封装的效果。(所谓古语曰:防君子不防小人)
- 封装演示实例:
1、比较low的封装
class Dog:
def __init__(self, name):
self.hidden_name = name
dog = Dog('哈士奇')
# print(dog.hidden_name)
dog.name = '田园犬'
print(dog.hidden_name)
打印输出结果:
哈士奇
分析:使用这种方式过于简单,只是简单的对哈士奇进行了封装,田园犬这个属性没有对哈士奇这个属性产生影响。
2、封装实例演示:
class Dog:
def __init__(self, name):
self.hidden_name = name
# getter()--查看属性方法:(可读)
def getter_name(self):
print('用户调用了此读取方法')
return self.hidden_name
# setter()--修改属性方法:(可写)
def setter_name(self, name):
print('用户调用了此修改方法')
self.hidden_name = name
dog = Dog('哈士奇')
dog.setter_name('田园犬')
print(dog.getter_name())
打印输出结果:
用户调用了此修改方法
用户调用了此读取方法
田园犬
分析:首先,在代码内部定义出了读取方法和修改方法,就证明,该代码内部的封装属性是可以修改的。
总结: 封装确实增加了类的定义的负责程度,但是也保证了数据的安全。
- 1.隐藏属性名,使调用者无法随意的修改对象中的属性。
- 2.增加了getter()方法和setter()方法,很好控制属性是否是只读的。
- 3.使用setter()方法设置属性,可以在再做一个数据的验证。
- 4.使用getter()方法获取属性,使用setter()方法设置属性可以读取属性和修改属性的同时做一些其他的处理。
3、真正意义上的封装
class Person:
def __init__(self, name):
self._name = name
# getter()--查看属性方法:(可读)
def getter_name(self):
print('用户调用了此读取方法')
return self._name
# setter()--修改属性方法:(可写)
def setter_name(self, name):
print('用户调用了此修改方法')
self._name = name
p1 = Person('陈慧翎')
p1.setter_name('周慧敏')
# print(p1._name) # 未调用get方法禁止查看属性
# p1.name = '黄一琳'
# print(p1.name)
print(p1.getter_name())
打印输出结果:
用户调用了此修改方法
用户调用了此读取方法
周慧敏
总结:
__name的意思是禁止修改此属性(相当于加了一层).
四、property装饰器
- property装饰器
- 我们可以适应@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的制只读属性,可以与虽定义的属性配合使用,这样可以防止属性被修改。
演示示例:
class Person:
def __init__(self, name):
self._name = name
@property # 设置只读属性(与getter方法类似)
def name(self):
print('getter方法执行了')
return self._name
@name.setter # 代表setter方法
def name(self, name):
print('setter方法执行了')
self._name = name
p1 = Person('周慧敏')
p1.name = '黄一琳'
print(p1.name)
打印输出结果:
setter方法执行了
getter方法执行了
黄一琳
总结:首先通过装饰器设置只读属性,再通过装饰器设置setter可修改属性,就可以告诉其他的同事,这是一个封装的参数,如果需要修改请通过正当方式修改。
五、PEP8代码书写规范
- 缩进使用4个空格,空格是首选的缩进方式,python3不允许混合使用制表符和空格来缩进。
- 每一行最大长度限制在79个字符以内。
- 顶层函数、类的定义。前后使用两个空行隔开。
- import导入
- 建议在不同的行导入,例如
import os
omport sys
也可以这样:
from subprocess import Popen, PIPE
- 导包位于文件顶部,在模块注释、文档字符串之后,全局变量、常量之前,导入按照以下顺序分组:
标准库导入
相关第三方库导入
本地应用/库导入
在每一组导入之间加入空行 - python中定义字符串使用双引号、单引号是相同的,尽量保持使用同一方式定义字符串,当一个字符串包包含单引号或者双引号时,在做外层使用不同的符号来避免使用反斜杠转译,从而提高可读性。
- 百搭是个语句中的空格:
1.避免在小括号、方括号、花括号后跟空格。
2.避免在都好、分号、冒号之前添加空格。
3.冒号在切片中就像二元运算符,两边要有相同数量的空格,如果某个切片参数省略,空格也省略。
4.避免为了和另外一个赋值语句对齐,在赋值运算符附加多个空格。
5.避免在表达式尾部添加空格,因为表达式尾部空格通常看不见,会产生混乱。
6.总是在二元运算符两边加一个空格,赋值(=),增量赋值(+=,-=),比较(==,<,>,!=,<>,<=,>=,in,not,in,is.is not),布尔(and,偶然,not)
7.避免将小的代码和if/for/while放在同一行,要避免代码太长。
1 if foo == 'blah': do_blah_thing()
2 for x in lst: total += x
3 while t < 10: t = delay()
- 永远不要使用字母’l’(L),o(O)或者大写的I作为字符串的变量,在有些字体里这些字符无法和数字0和1区分。
- 累名一般使用首字母大写的约定。
- 函数名应该小写,如果想提高可读性可以用下划线分割
- 如果函数的参数名和已有的关键词冲突,在做后加单一下划线比缩写或者随意拼写更好。
- 方法名和实例变量使用下划线分隔的小写单词,以提高可读性。