python learning OOP2.py
class Student(object):
pass
s = Student()
s.name = 'Chang' # 给一个实例动态绑定一个属性
print(s.name)
def set_age(self, age):
self.age = age
from types import MethodType
s.set_age = MethodType(set_age, s) # 给一个实例动态绑定一个方法
s.set_age(25)
print(s.age)
s2 = Student()
'''
s2.set_age(25) # 会报错
给一个实例动态绑定的方法对另一个实例不起作用
'''
def set_score(self, score):
self.score = score
Student.set_score = set_score # 给所有实例都绑定方法,可以给class绑定方法:
# 给class绑定方法后,所有实例均可调用:
s.set_score(100)
print(s.score)
s2.set_score(99)
print(s2.score)
# 动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。
# __slots__ : 限制实例的属性
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
s = Student()
s.name = 'Michael'
s.age = 25
# s.score = 99 # 报错 AttributeError: 'Student' object has no attribute 'score'
class GraduateStudent(Student):
pass
g = GraduateStudent()
g.score = 9999 # __slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
# 在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
##################################################
# 使用@property 来进行输入检测
s = Student()
s.age = 9999 # 这显然不合理
# 普通的方法就是在构造函数里加限制条件
class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise TypeError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 and 100!')
self._score = value
s = Student()
s.set_score(60) # ok
print(s.get_score()) # 60
# s.set_score(9999) # error
# 然而上述调用方式稍显复杂,能不能用类似 属性 这样简单的方式来访问类的变量
# Python内置的@property装饰器就是负责把一个方法变成属性调用的:
class Student(object):
# getter 变成属性,加上一行 @property 就可以了
@property
def score(self):
return self._score
# @property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
@score.setter
def score(self, value):
if not isinstance(value, int):
raise TypeError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
s = Student()
s.score = 60 # score.setter
print(s.score) # score
# s.score = 9999 报 typeerror 错
# 定义只读属性:只定义 getter 不定义 setter
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2018 - self._birth
# 上面的birth是可读写属性,而age就是一个只读属性
s = Student()
s.birth = 1996
print(s.birth)
print(s.age)
# s.age = 100 # 报错:can't set attribute
# 练习:
# 请利用@property给一个Screen对象加上width和height属性,以及一个只读属性resolution:
class Screen(object):
@property
def width(self):
return self._width # 变量名和函数名要区分开,不然会死循环
@width.setter
def width(self, value):
self._width = value
@property
def height(self):
return self._height
@height.setter
def height(self, value):
self._height = value
@property
def resolution(self):
return self._width * self._height # 一个和C++很不相同的地方,在类内写属性也要加 slef. 前缀
# 测试:
s = Screen()
s.width = 1024
s.height = 768
print('resolution =', s.resolution)
if s.resolution == 786432:
print('测试通过!')
else:
print('测试失败!')
##################################################
# 多重继承
class Animal(object): # 基类
pass
class Mammal(Animal): # 哺乳动物
pass
class Bird(Animal): # 鸟类
pass
class Runnable(object): # 能跑
def run(self):
print('Running...')
class Flyable(object): # 能飞
def fly(self):
print('Flying...')
class Dog(Mammal, Runnable): # 狗
pass
class Bat(Mammal, Flyable): # 蝙蝠
pass
class Parrot(Bird, Flyable): # 鹦鹉
pass
class Ostrich(Bird, Runnable): # 鸵鸟
pass
# MixIn
'''
# 举个例子,Python自带了TCPServer和UDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixIn和ThreadingMixIn提供。通过组合,我们就可以创造出合适的服务来。
# 比如,编写一个多进程模式的TCP服务,定义如下:
class MyTCPServer(TCPServer, ForkingMixIn):
pass
# 编写一个多线程模式的UDP服务,定义如下:
class MyUDPServer(UDPServer, ThreadingMixIn):
pass
'''
# 定制类
class Student(object):
def __init__(self, name):
self.name = name
print(Student('Micheal')) # <__main__.Student object at 0x00000140EEBFC320>
# 自定义打印实例信息
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name: %s)' % self.name
__repr__ = __str__ # __str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。
print(Student('Micheal'))
# __iter__
# 如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
class Fib(object):
def __init__(self):
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > 100:
raise StopIteration() # 迭代的停止条件
return self.a
for n in Fib():
print(n)
# __getitem__
# Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行
# 不能通过 Fib()[5] 取元素
# 要想使用下标来取元素,需要实现 __getitem__() 方法
class Fib(object):
def __getitem__(self, n):
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
f = Fib()
for x in range(10):
print(f[x])
# 实现切片
class Fib(object):
def __getitem__(self, n):
if type(n) == int:
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
if type(n) == slice:
start = n.start
stop = n.stop
if start is None:
start = 0
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
f = Fib()
for x in range(10):
print(f[x])
print(f[0:5])
print(f[:10])
# 与之对应的是__setitem__()方法,把对象视作list或dict来对集合赋值。
# 最后,还有一个__delitem__()方法,用于删除某个元素。
# __getattr__
# 正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。
# 要避免这个错误,除了可以加上这个属性外,Python还有另一个机制,那就是写一个__getattr__()方法,动态返回一个属性。
class Student(object):
def __init__(self):
self.name = 'Michael'
def __getattr__(self, attr):
if attr == 'score':
return 99
if attr == 'age':
return lambda:24
raise AttributeError('no such a attribute.')
# 当调用不存在的属性时,比如score,Python解释器会试图调用__getattr__(self, 'score')来尝试获得属性,这样,我们就有机会返回score的值:
# 注意,只有在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找。
s = Student()
print(s.name)
print(s.score)
print(s.age()) # 返回函数也可以,但相应的调用方式要变
# print(s.abc)
# 这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要任何特殊手段。
# __call__
# 在实例本身上调用
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s' % self.name)
s = Student("chang")
s()
# __call__()还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象
# 怎么判断一个变量是对象还是函数呢?其实,更多的时候,我们需要判断一个对象是否能被调用
# 使用 Callalbe 来判断类中有 __call__() 的类实例
print(callable(s))
# 枚举类
# Python 中实现常量定义
JAN = 1
FEB = 2
PI = 3.1415
# 缺点是 仍是变量
# 更好的方法是为这样的枚举类型定义一个class类型,每个常量都是class的一个唯一实例。Python提供了Enum类来实现这个功能:
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
# Month类型的枚举类,直接使用Month.Jan来引用一个常量,或者枚举它的所有成员,value属性则是自动赋给成员的int常量,默认从1开始计数
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
python learning OOP2.py的更多相关文章
- python learning IO.py
f = open('test.txt', 'r') # 'r' 表示只读 s = f.read() # 调用read()方法可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示 ...
- python learning OOP1.py
class Student(object): # 构造函数 # 第一个参数永远是 self 表示一个实例本身,但是传参的时候不需要传 # 在Python中,实例的变量名如果以__开头,就变成了一个私有 ...
- python learning Exception & Debug.py
''' 在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因.在操作系统提供的调用中,返回错误码非常常见.比如打开文件的函数open(),成功时返 ...
- Python Learning
这是自己之前整理的学习Python的资料,分享出来,希望能给别人一点帮助. Learning Plan Python是什么?- 对Python有基本的认识 版本区别 下载 安装 IDE 文件构造 Py ...
- python下编译py成pyc和pyo
python下编译py成pyc和pyo 其实很简单, 用 python -m py_compile file.py python -m py_compile /root/src/{file1,f ...
- python 装 ez_setup.py 出错
python 装 ez_setup.py出错setuptools,pip,install,UnicodeDecodeError: 'ascii' codec can't decode byte.解决: ...
- python中__init__.py文件的作用
问题 在执行models.py时,报ImportError:No module named transwarp.db的错误,但明明transwarp下就有db.py文件,路径也没有错误.真是想不通.后 ...
- Python的__init__.py用法
python中包的引入,对于大型项目中都会使用到这个功能,把实现不同功能的python文件放在一起,组成不同lib库,然后在其他地方调用. 包,python源文件+__init__.py 模块,pyt ...
- python d:\test.py File "<stdin>", line 1 python d:\test.py ^ SyntaxError: invalid syntax
pyhton出错: python d:\test.py File "<stdin>", line 1 python d:\test.py ^SyntaxError: i ...
随机推荐
- Linux—文件命令之touch命令
下面总结一下对于文件的操作命令: satat命令:用于显示文件的详细信息,包括文件.设备.gid.各种时间等. 命令格式:stat filename touch 的两个功能: 1.新建文件,如需建立特 ...
- OpenCV学习系列(一) Mac下OpenCV + xcode人脸检测实现
# OpenCV学习系列(一) Mac下OpenCV + xcode人脸检测实现 [-= 博客目录 =-] 1-学习目标 1.1-本章介绍 1.2-实践内容 1.3-相关说明 2-学习过程 2.1-环 ...
- Linux命令学习笔记1
1.Linux命令学习 2.Mkdir /data -创建文件夹 在/下创建文件夹 data 3.Cd -目录切换 列如cd / 4.Touch /data/1 ...
- c++ 字符串转换
字符分类函数 转换字符函数 字符串转换成数值 需清加#include<ctype.h> 函数名 功能 islower 测试是否小写字母, 是返回非零,否则返回零. isupper 测试是否 ...
- Kubernetes学习之路(六)之创建K8S应用
一.Deployment的概念 K8S本身并不提供网络的功能,所以需要借助第三方网络插件进行部署K8S中的网络,以打通各个节点中容器的互通. POD,是K8S中的一个逻辑概念,K8S管理的是POD,一 ...
- Storm 第四章 Storm常见问题
1.集群如何启动,任务如何执行? java -server nimbus,supervisor client--->createTopology(序列化)--->提交jar到nimbusi ...
- Git使用教程(一)---本地git管理
之前写过不少小demo,因为没有很好的整理,很多demo都找不到了,必要的时候又要重新写这些demo:这是一个很头疼的问题,很烦躁.网上看到git的版本控制以及托管,很nice.开始学习使用git,关 ...
- Datawhale MySQL 训练营 Task4 表联结
学习内容 MySQL别名 列别名,将查询或者筛选出来列用AS 命名,如果有空格则需要引号 '' SELECT xxx AS xxxx FROM WHERE GROUP BY HAVING 表别名, 把 ...
- 搭建好看的静态博客(使用Hexo进行搭建)
经常看到大牛的博客非常的高大帅气,虽然我很渣,但是逼格不能输,所以有了以下的搭建记录. 我的成果ninwoo,喜欢的可以参考下面的记录一起来动手搞起来. 安装Git Bash 访问git下载最新版本的 ...
- linux-shell-screen后台调用-后台运行脚本和命令-仿start命令-伪窗口界面
序 我比较熟练bat.cmd脚本.刚接触使用shell时,总会习惯想用windows窗口界面来套用shell脚本.于是找到screen后台命令,它可以交互shell脚本,保持后台运行.但是在批处理ba ...