目录
python对于类和实例,,都能随时动态绑定 属性或者函数
可以通过__slots__去限定实例所能绑定属性的范围
python里面类很多定制函数__xx__
下面给个python里面枚举类型
对type函数去实现
有关迭代器:
生成器:
可迭代对象:
有关python继承你需要了解
python对于类和实例,,都能随时动态绑定 属性或者函数
print('ABC'.lower())
class TT(object):
pass
def func(self,arg):
self.arg=arg
print(self.arg)
#python这个动态语言允许,在运行时给类或者实例去绑定新的属性/函数
#对这个类绑定了func,就相当于在TT类里面实现了一个func函数
#这是其他静态语言所不允许的
TT.func=func
TT.func(TT(),5)
t=TT()
t.func(6)
注意属性并不是一定需要的,,可有可无,只是稍微简单了一下代码
可以通过__slots__去限定实例所能绑定属性的范围
但是对于类本身来说没什么区别,,想添加属性也是可以的
#如果想对实例的属性做限制 可以用__slots__
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
#实例一个Student对象
s=Student()
s.socre=50 #不可以,,类做了限制,,实例绑定属性只能绑定name和age
s.age=0
s.name='sad'
Student.socre=10 #但是对于类本身来说没什么区别,,想添加属性也是可以的
print(Student.socre)
print(Student.age)
注意 __slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:
class boy(Student):
pass
bo=boy()
bo.socre=50
print(bo.socre)
这样是ok的, 想要再限制,那就在子类做__slots__限制
对于python来说私有 就是在前面加__两个杠去表示,属性啊,方法,变量等等都可以用
继承的话,子类没法继承父类的私有的东西,就没法直接使用
对于 非要想在外部去使用私有的东西,方法如下:_xx.__私有 ,不建议
如果想要对函数参数做检查,一般写起来函数内部比较麻烦,需要搞个set,get方法,,使用@property装饰器,可以把方法变为属性调用
把一个getter方法变成属性,只需要加上@property
就可以了,此时,@property
本身又创建了另一个装饰器@score.setter
,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:
class Student(object):
@property
def socre(self):
return self._socre
@socre.setter
def socre(self,value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._socre = value
s=Student()
s.socre=60 #方法当作属性去调用了 s.set_socre(60)
print(s.socre) #其实就是s.get_socre()
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2015 - self._birth
s=Student()
s.birth=15
print(s.age)
Python内置有三大装饰器:@staticmethod(静态方法)、@classmethod(类方法)、@property(描述符),其中静态方法就是定义在类里的函数,并没有非要定义的必要;类方法则是在调用类属性、传递类对象时使用;而@property则是一个非常好用的语法糖。@property最大的好处就是在类中把一个方法变成属性调用,起到既能检查属性,还能用属性的方式来访问该属性的作用。
可以通过装饰器去访问到类的私有成员
@property应用
让我们先看下@property的应用,其功能1是可定义只读属性,也就是真正意义上的私有属性(属性前双下划线的私有属性也是可以访问的,具体参照这篇文章:私有属性真的是私有的吗?)。实例需求是定义类Person,具有年龄和姓名,要求年龄必须等于18,则代码如下:
class Person(object):
def __init__(self, name, age=18):
self.name = name
self.__age = 18
@property
def age(self):
return self.__age
xm = Person('xiaoming') #定义一个人名小明
print(xm.age) #结果为18
xm.age = -4 #报错无法给年龄赋值
print(xm.age)
在python中定义只读属性非@property莫属,如果细心留意大部分源码,都跑不了@property的身影。而定义只读属性也很简单:以需要定义的属性为方法名(上例age属性定义为方法),其上装饰内置装饰器@property就ok了。
@property真正强大的是可以限制属性的定义。往往我们定义类,希望其中的属性必须符合实际,但因为在__init__里定义的属性可以随意的修改,导致很难实现。如我想实现Person类,规定每个人(即创建的实例)的年龄必须大于18岁,正常实现的话,则必须将属性age设为只读属性,然后通过方法来赋值,代码如下:
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = 18
@property
def age(self):
return self.__age
def set_age(self, age): #定义函数来给self.__age赋值
if age < 18:
print('年龄必须大于18岁')
return
self.__age = age
return self.__age
xm = Person('xiaoming', 20)
print(xm.age)
print('----------')
xm.set_age(10)
print(xm.age)
print('----------')
xm.set_age(20)
print(xm.age)
可以看到,通过方法的确能限制输入,但是不是每个人都记得方法名,有什么简化的方法呢?@property就能很轻松办到,修改代码如下:
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = 18
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
if age < 18:
print('年龄必须大于18岁')
return
self.__age = age
return self.__age
xm = Person('xiaoming', 20)
print(xm.age)
print('----------')
xm.age = 10
print(xm.age)
print('----------')
xm.age = 20
print(xm.age)
结果和上图一致。两段代码变化的内容:将set_age修改为age,并且在上方加入装饰器@age.setter。这就是@property定义可访问属性的语法,即仍旧以属性名为方法名,并在方法名上增加@属性.setter就行了。
python里面类很多定制函数__xx__
这里不说了
向打开文件的with方法,内部就是封装了相对的__enter__和__exit__
下面给个python里面枚举类型
下面是用enum函数去创建枚举类,也可以自己写类去继承Enum,去实现一个枚举类
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
type()
函数既可以返回一个对象的类型,又可以创建出新的类型,比如,我们可以通过type()
函数创建出Hello
类,而无需通过class Hello(object)...
的定义:
对于这个类:
class Hello(object):
def hello(self, name='world'):
print('Hello, %s.' % name)
对type函数去实现
def fn(self, name='world'): # 先定义函数
print('Hello, %s.' % name)
Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
h = Hello()
h.hello()
print(type(Hello))
print(type(h))
要创建一个class对象,type()
函数依次传入3个参数:
- class的名称;
- 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
- class的方法名称与函数绑定,这里我们把函数
fn
绑定到方法名hello
上。
通过type()
函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()
函数创建出class。
有关迭代器:
生成器:
可迭代对象:
执行__iter__返回了迭代器对象或者生成器对象,之后就进到迭代器或者生成器,,然后自动调__next__,这样就是达到了for循环。 python的for循环 或者range或者常见的数据类型比如list,元组,字典等等 对象其实都是返回可迭代对象,都是可以迭代的。
有关python继承你需要了解
但是对于复杂的继承关系,我们可以通过mro方法去获得这个类的继承关系