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)