1. */
  2. * Copyright (c) 2016,烟台大学计算机与控制工程学院
  3. * All rights reserved.
  4. * 文件名:text.cpp
  5. * 作者:常轩
  6. * 微信公众号:Worldhello
  7. * 完成日期:2016731
  8. * 版本号:V1.0
  9. * 程序输入:无
  10. * 程序输出:见运行结果
  11. */

特殊方法(魔术方法)

__str__和__repr__

如果要把一个类的实例变成 str,就需要实现特殊方法__str__():

class Person(object):

def
__init__(self, name, gender):

self.name = name

self.gender = gender

def
__str__(self):

return '(Person: %s, %s)' % (self.name, self.gender)

现在,在交互式命令行下用 print 试试:

>>> p = Person('Bob', 'male')

>>> print p

(Person: Bob, male)

但是,如果直接敲变量 p

>>> p

<main.Person object at 0x10c941890>

似乎__str__() 不会被调用。

因为 Python 定义了__str__()__repr__()两种方法,__str__()用于显示给用户,而__repr__()用于显示给开发人员。

有一个偷懒的定义__repr__的方法:

class Person(object):

def __init__(self, name, gender):

self.name = name

self.gender = gender

def __str__(self):

return '(Person: %s, %s)' % (self.name, self.gender)

__repr__ = __str__

__cmp__

对 intstr 等内置数据类型排序时,Python的 sorted() 按照默认的比较函数 cmp 排序,但是,如果对一组 Student 类的实例排序时,就必须提供我们自己的特殊方法 __cmp__():

class Student(object):

def __init__(self, name, score):

self.name = name

self.score = score

def __str__(self):

return '(%s: %s)' % (self.name, self.score)

__repr__ = __str__

def __cmp__(self, s):

if self.name < s.name:

return -1

elif self.name > s.name:

return 1

else:

return 0

上述 Student 类实现了__cmp__()方法,__cmp__用实例自身self和传入的实例 进行比较,如果 self 应该排在前面,就返回
-1,如果 s 应该排在前面,就返回1,如果两者相当,返回 0。

Student类实现了按name进行排序:

>>> L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 77)]

>>> print sorted(L)

[(Alice: 77), (Bob: 88), (Tim: 99)]

注意: 如果list不仅仅包含 Student 类,则 __cmp__ 可能会报错:

L = [Student('Tim', 99), Student('Bob', 88), 100, 'Hello']

print sorted(L)

__len__

如果一个类表现得像一个list,要获取有多少个元素,就得用 len() 函数。

要让 len() 函数工作正常,类必须提供一个特殊方法__len__(),它返回元素的个数。

例如,我们写一个 Students 类,把名字传进去:

class Students(object):

def __init__(self, *args):

self.names = args

def __len__(self):

return len(self.names)

只要正确实现了__len__()方法,就可以用len()函数返回Students实例的“长度”:

>>> ss = Students('Bob', 'Alice', 'Tim')

>>> print len(ss)

3

数学运算

Python 提供的基本数据类型 int、float 可以做整数和浮点的四则运算以及乘方等运算。

但是,四则运算不局限于int和float,还可以是有理数、矩阵等。

要表示有理数,可以用一个Rational类来表示:

class Rational(object):

def __init__(self, p, q):

self.p = p

self.q = q

p、q 都是整数,表示有理数 p/q。

如果要让Rational进行+运算,需要正确实现__add__:

class Rational(object):

def __init__(self, p, q):

self.p = p

self.q = q

def __add__(self, r):

return Rational(self.p * r.q + self.q * r.p, self.q * r.q)

def __str__(self):

return '%s/%s' % (self.p, self.q)

__repr__ = __str__

现在可以试试有理数加法:

>>> r1 = Rational(1, 3)

>>> r2 = Rational(1, 2)

>>> print r1 + r2

5/6

类型转换

Rational类实现了有理数运算,但是,如果要把结果转为 int  float 怎么办?

考察整数和浮点数的转换:

>>> int(12.34)

12

>>> float(12)

12.0

如果要把 Rational 转为 int,应该使用:

r = Rational(12, 5)

n = int(r)

要让int()函数正常工作,只需要实现特殊方法__int__():

class Rational(object):

def __init__(self, p, q):

self.p = p

self.q = q

def __int__(self):

return self.p // self.q

结果如下:

>>> print int(Rational(7, 2))

3

>>> print int(Rational(1, 3))

0

同理,要让float()函数正常工作,只需要实现特殊方法__float__()

@property

考察 Student 类:

class Student(object):

def __init__(self, name, score):

self.name = name

self.score = score

当我们想要修改一个 Student 的 scroe 属性时,可以这么写:

s = Student('Bob', 59)

s.score = 60

但是也可以这么写:

s.score = 1000

显然,直接给属性赋值无法检查分数的有效性。

如果利用两个方法:

class Student(object):

def __init__(self, name, score):

self.name = name

self.__score = score

def get_score(self):

return self.__score

def set_score(self, score):

if score < 0 or score > 100:

raise ValueError('invalid score')

self.__score = score

这样一来,s.set_score(1000) 就会报错。

这种使用 get/set 方法来封装对一个属性的访问在许多面向对象编程的语言中都很常见。

但是写 s.get_score() 和 s.set_score() 没有直接写 s.score 来得直接。

有没有两全其美的方法?----有。

因为Python支持高阶函数,在函数式编程中我们介绍了装饰器函数,可以用装饰器函数把 get/set 方法“装饰”成属性调用:

class Student(object):

def __init__(self, name, score):

self.name = name

self.__score = score

@property

def score(self):

return self.__score

@score.setter

def score(self, score):

if score < 0 or score > 100:

raise ValueError('invalid score')

self.__score = score

注意: 第一个score(self)是get方法,用@property装饰,第二个score(self, score)是set方法,用@score.setter装饰,@score.setter是前一个@property装饰后的副产品。

现在,就可以像使用属性一样设置score了:

>>> s = Student('Bob', 59)

>>> s.score = 60

>>> print s.score

60

>>> s.score = 1000

Traceback (most recent call last):

...

ValueError: invalid score

说明对 score 赋值实际调用的是 set方法

__slots__

由于Python是动态语言,任何实例在运行期都可以动态地添加属性。

如果要限制添加的属性,例如,Student类只允许添加 name、genderscore 这3个属性,就可以利用Python的一个特殊的__slots__来实现。

顾名思义,__slots__是指一个类允许的属性列表:

class Student(object):

__slots__ = ('name', 'gender', 'score')

def __init__(self, name, gender, score):

self.name = name

self.gender = gender

self.score = score

现在,对实例进行操作:

>>> s = Student('Bob', 'male', 59)

>>> s.name = 'Tim' # OK

>>> s.score = 99 # OK

>>> s.grade = 'A'

Traceback (most recent call last):

...

AttributeError: 'Student' object has no attribute 'grade'

__slots__的目的是限制当前类所能拥有的属性,如果不需要添加任意动态的属性,使用__slots__也能节省内存。

__call__

在Python中,函数其实是一个对象:

>>> f = abs

>>> f.__name__

'abs'

>>> f(-123)

123

由于 f 可以被调用,所以,f 被称为可调用对象。

所有的函数都是可调用对象。

一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()

我们把 Person 类变成一个可调用对象:

class Person(object):

def __init__(self, name, gender):

self.name = name

self.gender = gender

def __call__(self, friend):

print 'My name is %s...' % self.name

print 'My friend is %s...' % friend

现在可以对 Person 实例直接调用:

>>> p = Person('Bob', 'male')

>>> p('Tim')

My name is Bob...

My friend is Tim...

单看 p('Tim') 你无法确定 p 是一个函数还是一个类实例,所以,在Python中,函数也是对象,对象和函数的区别并不显著。

 

Python——13定制类的更多相关文章

  1. python基础——定制类

    python基础——定制类 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方 ...

  2. 快速了解Python的定制类

    多重继承 class Student(man,oldman): pass 可以继承多个父类,拥有他们的方法,如果有父类有相同的方法,哪个在前用哪个 定制类 看到类似__slots__这种形如 __xx ...

  3. python中定制类

    1.python中__str__和repr 如果要把一个类的实例变成 str,就需要实现特殊方法__str__(): class Person(object): def __init__(self, ...

  4. python 定制类

    看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让cla ...

  5. Python定制类(进阶6)

    转载请标明出处: http://www.cnblogs.com/why168888/p/6411919.html 本文出自:[Edwin博客园] Python定制类(进阶6) 1. python中什么 ...

  6. python定制类(1):__getitem__和slice切片

    python定制类(1):__getitem__和slice切片 1.__getitem__的简单用法: 当一个类中定义了__getitem__方法,那么它的实例对象便拥有了通过下标来索引的能力. c ...

  7. 【Python】__slots__ 、@property、多重继承、定制类、枚举类、元类

    __slots__ @property 多重继承 定制类 枚举类 元类 [使用__slots__] 1.动态语言的一个特点就是允许给实例绑定任意的方法和变量,而静态语言(例如Java)必须事先将属性方 ...

  8. Python面向对象 -- slots, @property、多重继承MixIn、定制类(str, iter, getitem, getattr, call, callable函数,可调用对象)、元类(type, metaclass)

    面向对象设计中最基础的3个概念:数据封装.继承和多态 动态给class增加功能 正常情况下,当定义了一个class,然后创建了一个class的实例后,可以在程序运行的过程中给该实例绑定任何属性和方法, ...

  9. Python基础(定制类)

    文章转载自廖雪峰老师Python课程博客,仅供学习参考使用看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道 ...

随机推荐

  1. [原]UEFI+GPT启动VHD

    1. 缘起 2. 创建VHD文件并写入系统镜像到VHD文件 2.1 制作VHD文件 2.1.1 纯界面创建 2.1.2 命令行创建 2.2 把系统镜像写入VHD文件 3. 添加VHD文件到系统引导 3 ...

  2. vue中axios的post请求使用form表单格式发送数据

    vue使用插件qs实现 (qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库.) 在jquery中的ajax的方法已将此封装,所以不需要再次序列化 1. 安装   在项目中使用命令行工具输 ...

  3. Linux之seq命令

    作用:seq命令用于以指定增量从首数开始打印数字到尾数,即产生从某个数到另外一个数之间的所有整数,并且可以对整数的格式.宽度.分割符号进行控制 语法: [1]  seq [选项]    尾数 [2]  ...

  4. 新年在家学java之基础篇--循环&数组

    因为“野味肺炎”的肆虐,过年被迫宅家只能吃了睡.睡了吃.这么下次只能长膘脑子空空,不如趁此机会重新学习java基础,为日后做铺垫~ 循环结构: 几种循环:for(::),while(){},do{}w ...

  5. Scapy-ARPspoof学习

    layout title tag date post Scapy模块学习之ARP欺骗 Python 2018-05-08 from scapy.all import Ether,ARP,sendp,g ...

  6. 17)C++开始--命名空间

    命名空间:就是区分同一个名字,在不同的作用域的变量 代码展示 #include<iostream> namespace spaceA{ ; namespace spaceB{ struct ...

  7. 记忆化dp博弈

    题:http://poj.org/problem?id=2068 题意: 有两个队伍A,B,每个队伍有N个人,交叉坐.即是A(1,3,5,7.....)B(2,4,6,8....).告诉你每个mi(1 ...

  8. plsql中文显示问号

    1. select userenv('language') from dual 2. 复制查询的值配置系统环境变量 NLS_LANG=AMERICAN_AMERICA.ZHS16GBK 3.配置系统环 ...

  9. Idea mac

    Idea 的破解 http://idea.lanyus.com/ Idea 的常用配置 模版及模版的使用 创建 JavaWeb 或 Module 关联数据库 版本控制 断点调试 配置 maven 其他 ...

  10. 02-Java开发环境的配置

    在本章节中我们将为大家介绍如何搭建Java开发环境. Windows 上安装开发环境 window系统安装java 下载JDK 首先我们需要下载java开发工具包JDK,下载地址:http://www ...