动态过程为类或者实例绑上一个方法
>>> def set_age(std,age):
std.age=age
#idle界面中敲出函数
>>> Student.set_age=MethodType(set_age,Student)
Traceback (most recent call last):File "<pyshell#41>", line 1, in <module>Student.set_age=MethodType(set_age,Student)
NameError: name 'MethodType' is not defined
#直接使用MethodType语句,发现不对
>>> from types import MethodType
>>> Student.set_age=MethodType(set_age,Student)
>>> bart=Student('bart',61,'male')
>>> bart.set_age(99)
>>> bart.age
99
#大功告成
image
Student.set_score = set_score
并不是给类绑定了方法只是调用,而Student.set_score=MethodType(set_score,Student)
才是给类绑定方法
1Student.set_score=set_scor print(Student.set_score,set_score)
2
Student.set_score=MethodType(set_score,Student) print(Student.set_score,set_score) 分别运行上面两段代码就能体会到区别
限制类里的属性__slots__
class Animals(object):
__slots__=('name','age')
class Cat(Animals):
pass
====
>>> Dogs=Animals()
>>> Dogs.name='doge'
>>> Dogs.age=7
>>> Dogs.number='A'
Traceback (most recent call last):File "<pyshell#52>", line 1, in <module>Dogs.number='A'
AttributeError: 'Animals' object has no attribute 'number'
#使用__slots__之后,Animal类的Dogs无法传入number属性
>>> Cats=Cat()
>>> Cats.number='A'
>>> Cats.number
'A'
#Animal的子类Cat却可以传入number属性
@property
为了解决调用函数代码复杂,直接暴露参数无法检查参数输入的矛盾,该语句应运而生。
class Student(object):
def __init__(self,name,score,gender):
self.__name=name
self.__score=score
self.__gender=gender
@property
#相当于调用时,使用变量名.函数名。即s.gender=,且表示该函数是只读的,不会修改
def gender(self):
return self.__gender
@gender.setter
#表示这是修改gender变量的函数
def set_gender(std, gender):
if gender=='male':
std.__gender=gender
elif gender=='female':
std.__gender=gender
else:
print('Type error')
在idle界面中
>>> bart=Student('bart',60,'male')
>>> bart.gender
'male'
>>> bart.set_gender='female'
>>> bart.gender
'female'
廖老师布置的作业:
# -*- coding: utf-8 -*-
class Screen(object):
def __init__(self,width=0,height=0):
self.__width=width
self.__height=height
@property
def width(self):
return self.__width
@property
def height(self):
return self.__height
@property
def resolution(self):
return self.__width*self.__height
@width.setter
def width(self,value):
if value>0:
self.__width=value
else:
print('Type Error')
@height.setter
def height(self,value):
if value>0:
self.__height=value
else:
print('Type Error')
多重继承
人类面临分类的时候经常会发现的问题:它既是一种分类方法的A类,又是另一种分类方法的B类。
此时,为了使得类可以完成它的使命,我们需要让他能够继承到他需要的属性,这就涉及了多重继承的问题。
class Animals(object):
__slots__=('name','age')
class Flyable(object):
pass
class Bat(Animals,Flyable):
pass
相当于tag标签一样的分类。
MixIn
摸不太着头脑,是说上面的那个Bat类还可以写成
class Bat(Animal,FlyableMixIn):
pass
吗?
定制类
__xxx__
类有特殊用途
注意,这些都是要自己写函数的,而不是可以直接在idle窗口调用的。它们写好后,可以让类的访问变得像是一个list型(或者其他类型)。
1 __str__
和__repr__
>>> a=Screen()
>>> a
<__main__.Screen object at 0x000001FA828B48D0>
此处返回的就是调用__repr__()
的,返回的是开发者看到的字符串,是为调试服务的。
可以这么写:
class Student(object):
def __init__(self,name,score,gender):
self.__name=name
self.__score=score
self.__gender=gender
def __str__(self):
return 'Student object (name=%s)' % self.__name
__repr__=__str__
idle界面:
>>> bart=Student('bart',60,'male')
>>> bart
Student object (name=bart)
2 __iter__
返回迭代
使用此语句返回一个迭代对象,使得在idle界面可以使用for循环访问。
3 __getitem__
返回一个可用下标访问的迭代对象
比如之前__iter__
返回的可迭代对象,用__getitem__
可以在idle界面使用下标如数列一样的访问。
但是要注意的是,在编写此函数时,要同时包含切片对象的处理方式。
同类还有,__setitem__
及__delitem__
等等
4 __getattr__
当用户访问一个不存在的属性时,python会调用__getattr__
函数。
因此,可以写:
#当访问一个不存在的属性时
def __getattr__(self,attr):
if attr=='age':
return 'unknown'
raise AttributeError('\'Student\' object has no attribute\'%s\''%attr)
idle中:
>>> bart=Student('bart',60,'male')
>>> bart.age
'unknown'
>>> bart.number
Traceback (most recent call last):
File "<pyshell#32>", line 1, in <module>
bart.number
File "D:\ZQC\2020寒假学习计划\python\Sy_13_WhereisDuiXiang.py", line 17, in __getattr__
raise AttributeError('\'Student\' object has no attribute\'%s\''%attr)
AttributeError: 'Student' object has no attribute'number'
#这个到底对不对啊,我好懵啊orz
5 __call__
可以将类的实例对象当成函数一样:
#类的实例当函数调用
def __call__(self):
print('I\'m class \'Student\'.')
idle中:
>>> bart=Student('bart',60,'male')
>>> bart()
I'm class 'Student'.
通过callable
可以判断一个对象是否可以调用。
使用枚举类
枚举类是一种定义常数的方法。
一般常量都是用全大写表示,如:PI=3.1415
。当然,这种定义方式太简单了,而且它本身是int型的变量。因此,就引出了,枚举类。
>>> from enum import Enum
>>> Week=Enum('week',('Mon','Tue','Wed','Thu','Fri','Sat','Sun'))
>>> for name,member in Week.__members__.items():
print(name,'-->',member.value)#列举所有枚举量
Mon --> 1
Tue --> 2
Wed --> 3
Thu --> 4
Fri --> 5
Sat --> 6
Sun --> 7
另外,还可以从Enum派生出自定义类:
>>> from enum import Enum
>>> class Weekday(Enum):
Sun=0
Mon=1
Tue=2
Wed=3
Thu=4
Fri=5
Sat=6
>>> day1=Weekday.Mon
>>> print(day1,Weekday.Tue,Weekday.Tue.value,day1==Weekday.Wed,Weekday(4))
Weekday.Mon Weekday.Tue 2 False Weekday.Thu
这里的访问两种方式都可以用。
成员值允许相同,第二个成员的名称被视作第一个成员的别名
使用元类
1 type()
>>> print(type(Weekday))#type()可以查看类型
<class 'enum.EnumMeta'>
>>> def fn(self,name='world'):#先定义函数
print('hello,%s'%name)
>>> Hello=type('Hello',(object,),dict(hello=fn))
#依次传入三个参数:class名,tuple表示的继承父类,class方法名绑定函数
>>> h=Hello()
>>> h.hello()
hello,world
>>> h.hello('Bob')
hello,Bob
2 metaclass
个人觉得,这玩意吧,会降低的代码可读性,因此放弃加载本节。
网友评论