文章目录
一、类属性与实例属性
1、类属性
(1)类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有。
(2)占用内存:类属性在内存中只存在 一个副本。
(3)作用域:可以通过类名或者对象名来访问
2、实例属性
(1) 即对象属性,它不被所有类对象的实例对象所共有。
(2)占用内存:在内存中的副本个数取决于对象个数,有几个对象,就有几个实例属性。
(3)作用域:只能通过对象名来访问
二、类方法与静态方法
1、类方法
类方法是类对象所拥有的方法,
需要用修饰器一般以@classmethod来标识其为类方法
1). 对于类方法,第一个参数必须是类名cls(形参)
2). 能够通过实例对象和类去访问。
import time
class Date(object):
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
def __str__(self):
return '%s-%s-%s' %(self.year, self.month, self.day)
@classmethod
def today(cls):
"""
类方法 @classmethod ,传入类名 Date
:return: 返回 类Date实例化出的对象
"""
now = time.localtime()
return cls(now.tm_year, now.tm_mon, now.tm_mday) # Date() 实例化对象
if __name__ == '__main__':
today = Date.today() # 通过类名直接访问 , today()方法返回当前日期对象
print(today) # 有魔术方法__str__可以友好展示,不然打印出的是一个日期对象 :<__main__.Date object at 0x000001A8CD4B95F8>
2、静态方法
静态方法需要用修饰器一般以@staticmethod来标识其为静态方法,
1). 静态方法不需要传任何参数
2). 能够通过实例对象和类去访问。
三、property类属性
1、定义
一种用起来像是使用的实例属性一样的特殊属性,可以对应于类的某个方法
使用:
定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数
调用时,无需括号
2、应用场景
(1)某个属性只能访问不能修改,将类方法转换成类属性
class Date(object):
def __init__(self, year, month, day):
self.__year = year # 定义为私有属性
self.__month = month
self.__day = day
@property # 将该私有属性用@property定义为一个函数,返回,则可以进行查看
def year(self):
return self.__year
@property
def month(self):
return self.__month
@property
def day(self):
return self.__day
if __name__ == '__main__':
dateobj = Date(2020, 1, 1)
print(dateobj.year, dateobj.month, dateobj.day) # 2020 1 1 则可以查看到私有属性
# 虽然year, month, day 都是方法,但是这里调用不用加(), 将类方法转换成了类属性
(2)某一个属性不能直接返回, 需要计算, 可以通过property属性实现
"""
分页显示是一种非常常见的浏览和显示大量数据的方法,属于web编程中最常处理的事件之一
类属性应用需求: 对于京东商城中显示电脑主机的列表页面,每次请求不可能把数据库
中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求
数据时就要显示的指定获取从第start条到第end条的所有数据 这个分页的功能包括:
• 根据用户请求的当前页和总数据条数计算出 start 和 end
• 根据start 和 end 去数据库中请求数据
"""
class Pagintor(object):
def __init__(self,page = 1, per_page = 5):
"""
:param page: 当前展示的页码
:param per_page: 每页显示的数据个数
"""
self.page = page
self.per_page = per_page
@property
def start(self):
return (self.page - 1) * self.per_page # 根据用户请求的展示页码和显示的数据个数计算出satrt
@property
def end(self):
return self.page * self.per_page # 根据用户请求的展示页码和显示的数据个数计算出end
goods = ['电脑'+str(i) for i in range(100)] # 列表生成式
if __name__ == '__main__':
pagintor = Pagintor(page = 2, per_page= 5)
inform = goods[pagintor.start: pagintor.end] # 切片
print('第%s页的商品信息为:%s' %(pagintor.page, inform)) #第2页的商品信息为:['电脑5', '电脑6', '电脑7', '电脑8', '电脑9']
3、property实现类属性的方式
类属性:在类中定义值为property对象的类属性
(1)通过函数实现
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = age # 定义私有属性
@property
def vaildAge(self):
return 0 < self.__age <= 150 # age 为property对象
# 设置property对象(age)的属性
def get_age(self): #获取age
if self.vaildAge:
return self.__age
else:
raise Exception('年龄不合法') # 抛出异常
def set_age(self, age): #修改设置age
if self.vaildAge:
self.__age = age
else:
raise Exception('年龄不合法')
def del_age(self): #删除age
if self.vaildAge:
print('年龄属性删除')
else:
raise Exception('年龄不合法')
# 通过函数的方式实现property类属性
age = property(fget=get_age, fset=set_age, fdel=del_age)
if __name__ == '__main__':
person = Person('张三', 18)
print(person.age)
person.age = 20
print(person.age)
del person.age
2、通过装饰器实现
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = age
@property
def vaildAge(self):
return 0 < self.__age <= 150
@property
def age(self): # age 为property对象
if self.vaildAge:
return self.__age
else:
raise Exception('年龄不合法')
# 通过装饰器实现类属性
@age.getter #获取age
def age(self):
if self.vaildAge:
return self.__age
else:
raise Exception('年龄不合法')
@age.setter # 修改设置age
def age(self, age):
if self.vaildAge:
self.__age = age
else:
raise Exception('年龄不合法')
@age.deleter # 删除age
def age(self):
if self.vaildAge:
print('年龄属性删除')
else:
raise Exception('年龄不合法')
if __name__ == '__main__':
person = Person('张三', 18)
print(person.age)
person.age = 20
print(person.age)
del person.age
四、元类type
1、定义
元类是类的类,是类的模板
元类的实例为类,正如类的实例为对象
元类就是创建类的类。函数type就是是元类。
Python中一切皆对象。包括整数、字符串、函数以及类都是对象,且都是从type类创建而来。
动态生成类,不能控制类是如何生成的。python3 的metaclass可动态创建类。
很多Web框架都会使用metaclass 来创建类。掌握元类对理解源代码至关重要。eg: ORM框架类
通过 __ class __ 的魔术方法 可以查看到,这些类的类是元类type。
类的本质是对象, 于是可以对类做如下的操作:
(1)可以将它赋值给一个变量
(2)可以拷⻉它
(3)可以为它增加属性
(4)可以将它作为函数参数进行传递
2、动态创建类
(1)通过分支语句动态创建类
因为类也是对象,运行时在函数中使用class关键字动态的创建类。 当使用class关键字时,Python解释器自动创建这个对象。当然Python提供手动处理的方法
def create_class(name):
if name == 'foo':
class Foo(object):
pass
return Foo
else:
class Bar(object):
pass
return Bar
cls = create_class(name='foo1')
print(cls.__name__)
(2)通过type动态创建类
语法格式:
type(类名, 父类名称的元组, 属性信息的字典)
def hello(self):
print('hello')
# 通过type创建类
Person = type('Person', (object, ), {'country' : 'China', 'hello': hello})
p = Person()
print(p.country)
p.hello()
3、自定义元类metaclass
应用场景:Django(ORM)、元类实现单例模式等
元类本身而言,实现的功能是: 1. 拦截类的创建 2. 修改类 3. 返回修改之后的类
class Example(type): # 自定义元类
pass
class Person(object, metaclass=Example): #指定元类为自定义出的Example
pass
五、抽象基类
1、定义
抽象基类有两个特点:
(1)规定继承类必须具有抽象基类指定的方法
(2)抽象基类无法实例化
基于上述两个特点,抽象基类主要用于接口设计
实现抽象基类需要使用内置的abc模块
import abc
class Human(metaclass=abc.ABCMeta):
"""定义一个抽象基类"""
@abc.abstractmethod # 抽象基类中的指定方法,继承的子类中需要重写
def introduce(self):
print('introduce...')
@property #继承的子类中需要重写
def country(self):
pass
@classmethod #继承的子类中需要重写
def gender(cls):
pass
@staticmethod #继承的子类中需要重写
def hello():
pass
def sayhello(self): # 继承的子类中不用重写
print('hello...')
class Person(Human):
def __init__(self, name , country, gender):
self.name = name
self.__country = country
self.gender = gender
def introduce(self): # 继承时,要重写抽象基类中的指定方法
print('123...')
@property
def country(self):
return self.__country
@classmethod
def gender(cls):
return 'female'
@staticmethod
def hello():
pass
if __name__ == '__main__':
#h = Human() # 抽象基类不能实例化
p = Person('张三', 'China', 'female')
p.introduce()
print(p.country)
p.sayhello()
六、自省机制
1、定义
(1)在日常生活中,自省(introspection)是一种自我检查行为。
(2)在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及 它能做什么。自省向程序员提供了极大的灵活性和控制力。
(3)例如Python, Ruby, object-C, C++都有自省的能力,这里面的C++的自省的能力最弱, 只能够知道是什么类型,而像Python可以知道是什么类型,还有什么属性。
2、Python中比较常见的自省机制(函数用法):
dir() #查看有什么方法,属性
type() #查看类型
hasattr() #查看是否有某个属性,属性写为字符串
setattr() #修改设置属性
getattr() #获取某个属性
delattr() #删除某个属性
isinstance() #判断是不是某个类型
通过这些函数,我们能够 在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。
七、slots限制对象属性
1、动态语言与静态语言的不同
动态语言:可以在运行的过程中,修改代码
静态语言:编译时已经确定好代码,运行过程中不能修改
2、__ slots __
Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性
使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
import time
class Date(object):
__slots__ = '__year', '__month', '__day' # 限制对象不能添加其他属性信息 , 只能有这三个属性信息
def __init__(self, year, month, day):
self.__year = year
self.__month = month
self.__day = day
@property
def year(self):
return self.__year
@property
def month(self):
return self.__month
@property
def day(self):
return self.__day
@classmethod
def today(cls):
time_t = time.localtime()
# cls是当前类 Date() 是实例化对象,
return cls(time_t.tm_year, time_t.tm_mon, time_t.tm_mday)
def __str__(self):
return '%s-%s-%s' % (self.__year, self.__month, self.__day)
d = Date(2020, 1, 1)
print("对象类型:", type(d)) # <class '__main__.Date'> 返回的是类名,他是由这个类创建出来的 就像以前type('s'),返回的是str,是他的类
print("判断是否有year这个属性:", hasattr(d, 'year'))
print("判断是否有time这个属性:", hasattr(d, 'time'))
# setattr(d,'day','9') 报错, 他是私有属性,用了@property只能查看不能修改
print('day属性为:', getattr(d, 'day'))
# setattr(d,'time','1:1:1') 报错, slots 限制了不能添加其他属性
# print('time属性为:', getattr(d,'time'))
print(Date.today())
运行结果: