Python基础(十二)—面向对象拾遗(__slots__、@property、枚举类、元类)
in python基础 with 0 comment

Python基础(十二)—面向对象拾遗(__slots__、@property、枚举类、元类)

in python基础 with 0 comment

编译型语言和解释型语言

动态语言和静态语言

使用__slots__

限制实例的属性

对实例绑定的属性或方法只对绑定实例有效,对另外实例无效。采用给class绑定,则对所有实例均有效。

class Student:
    pass

s1 = Student()
s1.name = 'lz'
print(s1.name)  # lz

s2 = Student()
# print(s2.name)  # 报错:AttributeError: 'Student' object has no attribute 'name'

def set_age(self, age):
    self.age = age
from types import MethodType
s1.set_age = MethodType(set_age, s1)
s1.set_age(17)
print(s1.age)  # 17,对s2不起作用

# 对实例绑定的属性或方法只对绑定实例有效,对另外实例无效。采用给class绑定,则对所有实例均有效。
Student.set_age = MethodType(set_age ,Student)
s3 = Student()
s3.set_age(20)
print(s3.age)  # 20
class Fish:
    __slots__ = ('name', 'age', 'sex')  # 如果这里没有sex,则下面的print会报错没有该属性

    def __init__(self, sex):
        self.sex = sex

f1 = Fish('man')
print(f1.sex)

# f1.size = 18  # 报错没有该属性

@property

@property广泛应用于类的定义中,可以简化代码,同时保证对参数进行必要的检查,检查程序运行的出错。

在Python基础(十)—面向对象的深入讲解(继承、Mixin编程机制等)章节中,说的是property(fget=None, fset=None, fdel=None, doc=None):通过类定义的属性设置属性。和@property有本质区别.

class Student:
    def get_sorce(self):
        return self.sorce
    def set_sorce(self, value):
        if not isinstance(value, int):
            raise ValueError('sorce必须是Int')
        if value < 0 or value > 100:
            raise ValueError('sorce必须介于0~100')
        self._sorce = value

单下划线和双下划线都是限定属性的私有

class Student:
    @property
    def sorce(self):
        return self.sorce

    @sorce.setter
    def set_sorce(self, value):
        if not isinstance(value, int):
            raise ValueError('sorce必须是Int')
        if value < 0 or value > 100:
            raise ValueError('sorce必须介于0~100')
        self._sorce = value
# 把一个getter方法加上@property,就变成了属性,同时@property本身又创建了另一个装饰器@sorce.setter,负责把一个setter方法变成属性赋值,这样就拥有了一个可控的属性操作。
class Man:
  @property
  def birth(self):
      return self._birth
  @birth.setter
  def birth(self, value):
      self._birth = value
  
  @property
  def age(self):
      return 2019-self._birth
  }

使用枚举类

from  enum import Enum
class VIP(Enum):
    YELLOW = 1
    RED = 2
    BLUE = 3
print(VIP.YELLOW) #枚举类型
print(VIP['YELLOW']) #枚举类型
print(VIP.YELLOW.name) #枚举名称
print(VIP.YELLOW.value)  #枚举值
print(VIP(3)) #数字得到枚举类型

#遍历
for v in VIP:  #遍历
    print(v)

# 成员的value默认从1开始
for name, member in VIP.__members__.items():
    print(name, "->", member, ',', member.value)
"""
YELLOW -> VIP.YELLOW , 1
RED -> VIP.RED , 2
BLUE -> VIP.BLUE , 3
"""
from enum import Enum, unique
@unique
class Mistake(Enum):
    ONE = 1
    TWO = 2
    THREE = 3
    FOUR = 3
"""
出错:ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
"""

枚举类型是使用单例模式实现的。在创建枚举类的时候,Python就在内存中为我们创建了枚举类的对象,因此我们不必实例化枚举类。并且由于枚举类的“new”方法,将会保证内存中只会存在一个枚举类的实例。

type()创建类

动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是在运行时动态创建的。

class Hello(object):
    def hello(self, name='world'):
        print('hello %s.' % name)

h = Hello()
print(type(Hello))  # <class 'type'>
print(type(h))   # <class '__main__.Hello'>

# Hello是一个class,类型为type,h是一个实例,它的类型就是class Hello
def hl(self, name='world'):
    print('hello %s.' % name)
Hello = type('Hello', (object,), dict(hello = hl))  # 创建Hello的类

h = Hello()
h.hello()
print(type(Hello))
print(type(h))
"""
hello world.
<class 'type'>
<class '__main__.Hello'>
"""

通过type()函数创建类与直接写class是完全一样的,因为Python解释器遇到class定义时,仅是扫描class定义的语法,然后调用type()进行创建class,这也就是动态语言支持运行期间创建类。

metaclass 元类

所以 metaclass 允许你创建类或修改类,也就是你可以把类看成是 metaclass 创建出来的“实例”。

Responses