Python【系列教程】之类和对象
【摘要】 一、定义类,对象,实例方法和自动绑定self
class Person: hair = 'black' # 构造方法 def __init__(self, name='Charlie', age=8): self.name = name self.age = age # 定义一个say方法 def say(self, content): print(content) ...
一、定义类,对象,实例方法和自动绑定self
class Person:
hair = 'black'
# 构造方法
def __init__(self, name='Charlie', age=8):
self.name = name
self.age = age
# 定义一个say方法
def say(self, content):
print(content)
p = Person()
print(p.name, p.age)
p.name = '李刚'
p.say('语言简单,学习很容易')
print(p.name, p.age)
p.skills = ['programming', 'swimming']
print(p.skills)
del p.name
# 删除p对象的name属性,再次访问的时候报错
# print(p.name)
# 动态给对象增加方法
def info(self):
print("--info函数--", self)
p.foo = info
p.foo(p)
p.bar = lambda self: print('--lambda表达式--', self)
p.bar(p)
"""上面分别用函数和lambda表达式为p对象动态增加了方法,但是对于动态
增加的方法,python不会自动将方法调用者绑定到它们的第一个参数,因此程序必须手动为第一个参数
传入参数值"""
"""如果希望动态增加的方法也能自动绑定到第一个参数,则可借助于types模块下的MethodType进行包装"""
def intro_func(self, content):
print("我是一个人,信息为:%s" % content);
# 导入MethodType
from types import MethodType
p.intro = MethodType(intro_func, p)
p.intro("生活在别处");
二、方法
class Bird:
# 使用@Classmethod修饰的方法是类方法
@classmethod
def fly(cls):
print('类方法fly:', cls)
# 使用@staticmethod修饰的方法是静态方法
@staticmethod
def info(p):
print('静态方法info:', p)
Bird.fly()
Bird.info("crazy")
b = Bird()
b.fly()
b.info("kit")
"""前面的静态方法和类方法的本质就是函数装饰器,
其中classmethod和staticmethod都是python内置的函数"""
def funA(fn):
print('A')
fn() # 执行传入的fn参数
return 'end'
@funA
def funB():
print('B')
print(funB)
"""上面的程序@funA修饰funB,这意味着程序要完成两步操作
将funB作为funA()的参数,也就是上面的粗体字码相当于执行funA(funB)
将funB替换成第1步执行的结果,funA()执行完成后返回fkit,因此funB
就不再是函数,而是被替换成一个字符串
"""
def foo(fn):
# 定义一个嵌套函数
def bar(*args):
print("====1====", args)
n = args[0]
print('====2====', n * (n - 1))
# 查看传给foo函数的fn函数
print(fn.__name__)
fn(n * (n - 1))
print("*" * 15)
return fn(n * (n - 1))
return bar
@foo
def my_test(a):
print('====my_test函数====', a)
print(my_test)
my_test(10)
my_test(6, 5)
# def auth(fn):
# def auth_fn(*args):
# print("模拟执行权限检查")
# fn(*args)
#
# return auth_fn
def auth(fn):
def auth_fn(*args):
print("模拟执行权限检查")
fn(*args)
return auth_fn
@auth
def test(a, b):
print("asdasdasdasd啊实打实大苏打")
test(20, 15)
"""上面介绍的这种在被修饰函数之前,之后,抛出异常后增加某种处理逻辑的方式
就是其他编程语言中的aop面向切面编程
"""
class item:
print('正在定义item类')
for i in range(10):
if i % 2 == 0:
print('偶数',1)
else:
print('奇数',1)
global_fn = lambda p:print('执行lambda表达式,p参数',p)
class category:
cate_fn = lambda p:print('执行lambda表达式,p参数',p)
global_fn('fkit')
c = category()
c.cate_fn()
三、成员变量
# 1.使用property函数定义属性
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def setSize(self, size):
self.width, self.height = size
def getSize(self):
return self.width, self.height
def delSize(self):
self.width, self.height = 0, 0
size = property(getSize, setSize, delSize, '用于描述矩形大小的属性')
print(Rectangle.size.__doc__)
help(Rectangle.size)
rect = Rectangle(4, 3)
# 相当于调用了getSize方法
print(rect.size)
rect.size = 9, 7
print(rect.width)
print(rect.height)
# 删除size,相当于删除了width属性和height属性
del rect.size
print(rect.width)
print(rect.height)
"""在某些编程语言中,类似于这种property合成的属性被称为计算属性。这种属性
并不真正存储任何状态,它的值其实是通过某种算法计算得到的,当程序对该属性赋值时,
被赋的值也会被存储到其他实例变量中
"""
"""还可以使用@property装饰器来修饰方法,使之成为属性"""
class Cell:
# 使用@property装饰器来修饰方法,相当于为该属性设置getter方法
@property
def state(self):
return self._state
# 为state属性设置setter方法
@state.setter
def state(self, value):
if 'alive' in value.lower():
self._state = 'alive'
else:
self._state = 'dead'
# 为is_dead属性设置getter方法
# 只有getter方法的属性是只读属性
@property
def is_dead(self):
return not self._state.lower() == 'alive'
c = Cell()
c.state = 'Alive'
print(c.state)
print(c.is_dead)
##################隐藏和封装################
class User:
def __hide(self):
print("示范隐藏的hide方法")
def getname(self):
return self.__name
def setname(self, name):
if len(name) < 3 or len(name) > 8:
raise ValueError('用户名必须在3~8之间')
self.__name = name
name = property(getname,setname)
u = User()
#__hide其实是python悄悄修改了方法名,将__hide修改成了_类名__hide()
u._User__hide()
u._User__name = 'fk'
print(u.name)
"""如果程序希望python类中的某些成员隐藏起来,那么只要让该成员的名字以双下划线开头即可。
即使通过这种机制实现了隐藏,其实也依然可以绕过去"""
四、类的继承
# 1.类的继承
class Fruit:
def info(self):
print('我是一个水果!重%g克' % self.weight)
class Food:
def taste(self):
print("不同食物的口感不同")
# 定义Apple类,继承了Fruit和Food类
class Apple(Fruit, Food):
pass
a = Apple()
a.weight = 5.6
# 调用水果类的info方法
a.info()
# 调用食物类的taste方法
a.taste()
class Item:
def info(self):
print("item中方法:", '这是一个商品')
class Product:
def info(self):
print("Product中方法:", "这是一个工业产品")
class Mouse(Item, Product):
pass
m = Mouse()
m.info()
"""Mouse继承了两个类,两个类具有相同的方法,但是Item排在Product的前面,
因此Item中定义的方法优先级更好,Python会优先到Item父类中搜寻方法,一旦
在Item父类中搜寻到目标方法,Python就不会继续向下搜寻了"""
# 重写父类的方法
class Bird:
# Bird类的fly()方法
def fly(self):
print('我在天空里自由自在的飞翔')
class Ostrich(Bird):
def fly(self):
print('我只能在地上奔跑')
# 创建Ostrich
os = Ostrich()
# 执行子类的fly方法,将输出我只能在地上奔跑
os.fly()
class BaseClass:
def foo(self):
print('父类中定义的foo方法')
class SubClass(BaseClass):
def foo(self):
print("子类重写父类中的foo方法")
def bar(self):
print('执行bar方法')
self.foo()
# 使用类名调用实例方法(未绑定方法)调用
BaseClass.foo(self)
sc = SubClass()
sc.bar()
# 使用super函数重写父类构造方法
class Employee:
def __init__(self, salary):
self.salary = salary
def work(self):
print('普通员工正在写代码,工资是:', self.salary)
class Customer:
def __init__(self, favorite, address):
self.favorite = favorite
self.address = address
def info(self):
print('我是一个顾客,我的爱好是:%s,地址是: %s' % (self.favorite, self.address))
class Manager(Employee,Customer):
def __init__(self,salary,favorite,address):
super(Manager,self).__init__(salary)
Customer.__init__(self,favorite,address)
m=Manager(25000,'it产品','广州')
m.work()
m.info()
五、python的动态性
############################################2.动态属性与_slots_
#动态的给Cat类添加方法
class Cat:
def __init__(self,name):
self.name = name
def walk_func(self):
print('%s 慢慢地走过一片草地' % self.name)
d1 =Cat('Garfield')
d2 =Cat('Kitty')
Cat.walk = walk_func
d1.walk()
d2.walk()
class Dog:
__slots__ = ('walk','age','name','foo')
def __init__(self,name):
self.name = name
def test(self):
print('预先定义的test方法')
d = Dog('snooy')
#只允许为实例动态的添加walk,age,name这三个属性或者方法
from types import MethodType
d.walk = MethodType(lambda self:print('%s 正在慢慢的走'),d)
d.age = 5
d.walk()
d.foo = 30
#__slots__并不限制通过类来动态添加方法
Dog.bar = lambda self: print('abc')
d.bar()
#####################3.使用type()函数定义类
def fn(self):
print("this is a 函数")
Dog = type('Dog',(object,),dict(walk=fn,age=6))
#创建Dog对象
d = Dog()
print(type(d))
print(type(Dog))
d.walk()
print(Dog.age)
"""type定义类的时候可以指定三个参数
参数一:创建的类名
参数二:该类继承的父类集合,由于python 支持多继承,因此此处使用元组指定它的多个父类。即使实际
只有一个父类,也需要使用元组语法(必须要多一个逗号)
参数三:该字典对象为该类绑定的类变量和方法。其中字典key就是变量名或者方法名,
如果字典的value是普通值,那就代表类变量,如果字典的value是函数,则代表方法。
"""
###########################4.使用metaclass
"""如果希望创建某一批类全部具有某种特征,可通过metaclass来实现,使用metaclass可在创建类的
时候动态修改类定义,为了使用metaclass动态修改类定义,程序需要先定义metaclass,metaclass应该继承
type类,并重写__new__()方法"""
class ItemMetaclass(type):
#cls代表被动态修改的类
#name代表被动态修改的类名
#bases代表被动态修改的类的所有父类
#attr代表被动态修改的类的所有属性,方法组成的字典
def __new__(cls, name,bases,attrs):
attrs['cal_price'] = lambda self: self.price * self.discount
return type.__new__(cls,name,bases,attrs)
class Book(metaclass=ItemMetaclass):
__slots__ = ('name','price','_discount')
def __init__(self,name,price):
self.name = name
self.price = price
@property
def discount(self):
return self._discount
@discount.setter
def discount(self,discount):
self._discount = discount
class CellPhone(metaclass=ItemMetaclass):
__slots__ = ('price', '_discount')
def __init__(self, price):
self.price = price
@property
def discount(self):
return self._discount
@discount.setter
def discount(self, discount):
self._discount = discount
"""上面定义的Book类和CellPhone类都指定了metaclass信息,因此当
python解释器在创建这两个类的时候,ItemMetaClass的__new__方法就会被调用,
用于修改这两个类,动态增加cal_price方法"""
b= Book("疯狂python讲义",89)
b.discount = 0.76
print(b.cal_price())
cp = CellPhone(2399)
cp.discount = 0.85
print(cp.cal_price())
"""metaclass这个功能在开发一些基础性框架时非常有用,程序可以通过
使用metaclass为某一批需要具有通用功能的类添加方法"""
六、多态
#################1.多态性
class Bird:
def move(self, field):
print('鸟在%s上自由的飞翔' % field)
class Dog():
def move(self, field):
print('狗在%s里飞快地奔跑' % field)
x = Bird()
# 调用x变量
x.move('天空')
x = Dog()
x.move('草地')
class Canvas:
def draw_pic(self, shape):
print('---开始绘图---')
shape.draw(self)
class R:
def draw(self, canvas):
print('在%s上绘制矩形' % canvas)
class T:
def draw(self, canvas):
print('在%s上绘制三角形' % Canvas)
class Circle:
def draw(self, canvas):
print('在%s上h绘制圆形' % canvas)
c = Canvas()
c.draw_pic(R())
c.draw_pic(T())
#################2.检查类型
"""python提供了两个函数来检查类型
issubclass(cls,class_or_tuple):检查cls是否是后一个类或者元组包含的多个类中任意类的子类
isinstance(obj,class_or_tuple):检查obj是否是后一个类或者元组包含的多个类中任意类的对象
通过使用上面两个函数,程序可以方便地先执行检查,然后才调用方法,这样可以保证程序不会出现
意外情况
"""
hello = "hello"
print(isinstance(hello, str))
print(issubclass(str, object))
print(isinstance(hello, tuple))
class A:
pass
class B:
pass
class C(A, B):
pass
print(C.__bases__)
print(B.__subclasses__())
"""类名.__bases__: 可查看该类所有直接父类
类名.__subclasses__():通过该方法可以查看该类的所有直接子类"""
########################3.枚举类
"""枚举的两种方式:
(1)直接使用Enum列出多个枚举值来创建枚举类
(2)通过继承Enum基类来派生枚举类
"""
import enum
Season = 'Season'
Season = enum.Enum(Season, ('SPRING', 'SUMMER', 'FALL', 'WINTER'))
print(Season.SPRING)
print(Season.SPRING.name)
print(Season.SPRING.value)
print(Season['SUMMER'])
print(Season(3))
for name,member in Season.__members__.items():
print(name,'=>',member,',',member.value)
class Orientation(enum.Enum):
#为序列值指定value值
east = '东'
south= '南'
west = '西'
north = '北'
def info(self):
print('这是一个代表方向【%s】的枚举' % self.value)
print(Orientation.south)
print(Orientation.south.value)
print(Orientation['west'])
print(Orientation('南'))
print(Orientation.east.info())
for name,member in Orientation.__members__.items():
print(name,'=>',member,',',member.value)
#枚举的构造器
import enum
class Gender(enum.Enum):
MALE = '男','阳刚之力'
FEMALE = '女','柔顺之美'
def __init__(self,cn_name,desc):
self._cn_name = cn_name
self._desc = desc
@property
def desc(self):
return self._desc
@property
def cn_name(self):
return self._cn_name
print(Gender.FEMALE.name)
print(Gender.FEMALE.value)
print(Gender.FEMALE.cn_name)
print(Gender.FEMALE.desc)
文章来源: blog.csdn.net,作者:血煞风雨城2018,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq_31905135/article/details/100554741
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)