类有两种属性:属性引用和实例化
属性引用(类名.属性)
class Person: #定义一个人类 role = ‘person‘ #人的角色属性都是人 def walk(self): #人都可以走路,也就是有一个走路方法 print("person is walking...") print(Person.role) #查看人的role属性 print(Person.walk) #引用人的走路方法,注意,这里不是在调用
实例化:类名加括号就是实例化,会自动出发__init__函数的运行,可以用它为每个实例定制自己的特性
类属性的补充
一:我们定义的类的属性到底存到哪里了?有两种方式查看 dir(类名):查出的是一个名字列表 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 二:特殊的类属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中)
面向对象小结:
class 类名: def __init__(self,参数1,参数2): self.对象的属性1 = 参数1 self.对象的属性2 = 参数2 def 方法名(self):pass def 方法名2(self):pass 对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西 #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法 #括号里传参数,参数不需要传self,其他与init中的形参一一对应 #结果返回一个对象 对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 即可 对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
对象之间的交互:
1 class Person: # 定义一个人类 2 role = ‘person‘ # 人的角色属性都是人 3 4 def __init__(self, name, aggressivity, life_value): 5 self.name = name # 每一个角色都有自己的昵称; 6 self.aggressivity = aggressivity # 每一个角色都有自己的攻击力; 7 self.life_value = life_value # 每一个角色都有自己的生命值; 8 9 def attack(self,dog): 10 # 人可以攻击狗,这里的狗也是一个对象。 11 # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降 12 dog.life_value -= self.aggressivity 13 14 class Dog: # 定义一个狗类 15 role = ‘dog‘ # 狗的角色属性都是狗 16 17 def __init__(self, name, breed, aggressivity, life_value): 18 self.name = name # 每一只狗都有自己的昵称; 19 self.breed = breed # 每一只狗都有自己的品种; 20 self.aggressivity = aggressivity # 每一只狗都有自己的攻击力; 21 self.life_value = life_value # 每一只狗都有自己的生命值; 22 23 def bite(self,people): 24 # 狗可以咬人,这里的狗也是一个对象。 25 # 狗咬人,那么人的生命值就会根据狗的攻击力而下降 26 people.life_value -= self.aggressivity 27 28 p = Person(‘alex‘, 10, 100) 29 d = Dog(‘erha‘, ‘big_dog‘, 10, 100) 30 print(d.life_value) # 查看d的生命值 31 p.attack(d) # p打了d 32 print(d.life_value) # d掉了10点血 33
1 from math import pi 2 3 class Circle: 4 ‘‘‘ 5 定义了一个圆形类; 6 提供计算面积(area)和周长(perimeter)的方法 7 ‘‘‘ 8 def __init__(self,radius): 9 self.radius = radius 10 11 def area(self): 12 return pi * self.radius * self.radius 13 14 def perimeter(self): 15 return 2 * pi *self.radius 16 17 18 circle = Circle(10) #实例化一个圆 19 area1 = circle.area() #计算圆面积 20 per1 = circle.perimeter() #计算圆周长 21 print(area1,per1) #打印圆面积和周长
面向对象的组合方法
1 class BirthDate: 2 def __init__(self,year,month,day): 3 self.year=year 4 self.month=month 5 self.day=day 6 7 class Couse: 8 def __init__(self,name,price,period): 9 self.name=name 10 self.price=price 11 self.period=period 12 13 class Teacher: 14 def __init__(self,name,gender,birth,course): 15 self.name=name 16 self.gender=gender 17 self.birth=birth 18 self.course=course 19 def teach(self): 20 print(‘teaching‘) 21 22 p1 = Teacher(‘alex‘, ‘male‘, 23 BirthDate(‘1996‘, ‘1‘, ‘27‘), 24 Course(‘python‘, ‘180000‘, ‘1 year‘) 25 ) 26 27 print(p1.birth.year, p1.birth.month, p1.birth.day) 28 # 1996 1 27 29 print(p1.course.name, p1.course.price, p1.course.period) 30 # python 180000 1 year
面向对象的三大特性
继承 多态 封装
1. 继承
一个类可以被多个类继承
一个类可以继承多个父类
1 class Animal: 2 def __init__(self): 3 print(‘执行Animal.__init__‘) 4 self.func() 5 def eat(self): 6 print(‘%s eating‘%self) 7 def drink(self): 8 print(‘%s drinkingg‘ % self) 9 def func(self): 10 print(‘Animal.func‘) 11 12 class Dog(Animal): 13 def guard(self): 14 print(‘guarding‘) 15 def func(self): 16 print(‘Dog.func‘) 17 dog = Dog() # 执行Animal.__init__ Dog.func
注意:
父类中没有的属性(方法), 在子类中出现,叫做派生属性(方法)
只要是子类的对象调用,子类中有的名字,一定要用子类的,子类中没有才找父类的,若父类也没用,则报错
如果还想要用父类的,则单独调用父类:
父类名.方法名 需要自己传参数
super.().方法名 不需要自己传参数
1 class Animal: 2 def __init__(self, name, aggr, hp): 3 self.name = name 4 self.aggr = aggr 5 self.hp = hp 6 def eat(self): 7 print(‘eating!!!‘) 8 9 class Dog(Animal): 10 def __init__(self, name, aggr, hp, kind): # 定义自己属性 11 # 方法1:直接用父类调用 12 Animal.__init__(self, name, aggr, hp) 13 self.kind = kind # 派生属性 14 class Person(Animal): 15 def __init__(self, name, aggr, hp, sex): 16 # 方法2: super指定父类 17 super().__init__(name, aggr, hp) 18 self.sex = sex # 派生属性 19 self.money = 0 20 21 jin = Dog(‘金老板‘,100,500,‘泰迪‘) 22 print(jin.name) 23 super(Dog, jin).eat() # super在外部调用,必须传类名和对象名
总结:
继承
单继承
先抽象再继承,几个类之间的相同代码抽象出来,成为父类
子类自己没有的名字,就可以使用父类的方法和属性
如果子类自己有,一定是先用自己的
在类中使用self的时候,一定要看清楚self指向谁
多继承
新式类和经典类:
多继承寻找名字顺序:新式类广度优先,经典类深度优先
新式类中有一个类名.mro()查看广度优先的继承顺序
python3中 有一个super()方法,根据广度优先的顺序查找上一个类
2. 多态 : python天生支持多态
3. 封装
原则: 将不需要对外提供的内容都隐藏起来
把属性都隐藏,提供公共方法对其访问
私有变量的私有方法
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式: class A: __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N def __init__(self): self.__X=10 #变形为self._A__X def __foo(self): #变形为_A__foo print(‘from A‘) def bar(self): self.__foo() #只有在类内部才可以通过__foo的形式访问到.
1 class Person: 2 __key = 123 3 def __init__(self, name, passwd): 4 self.name = name 5 self.__passwd = passwd # 私有变量 6 7 8 def get_pwd(self): 9 return self.__passwd # 只要在类的内部使用私有属性,就会自动的带上_类名 10 alex = Person(‘alex‘, ‘alex3714‘) 11 print(alex._Person__passwd) # 对象._类名__属性名
注:
所有的私有 都是在变量的左边加上双下划线
# 对象的私有属性
# 类中的私有方法
# 类中的静态属性
所有的私有的 都不能在类的外部使用
property属性
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
1 from math import pi 2 class Circle: 3 def __init__(self, r): 4 self.r = r 5 6 @property # 伪装成属性 7 def perimeter(self): 8 return 2*pi*self.r 9 10 def area(self): 11 return self.r**2*pi 12 c1 = Circle(5) 13 print(c1.area()) # 伪 圆的面积 14 print(c1.perimeter) # 装成属性 被@property伪装成属性 调用该方法名时候 不用加()
为什么要使用property?
将一个类的函数定义成property属性后,对象再去使用obj.area的时候根本无法察觉自己的area是执行了一个函数计算出来的,这种特性遵循了统一访问的原则
面向对象的封装有三种方式:
【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开
一个静态属性property本质就是实现了get,set,delete三种方法
1 class Goods: 2 3 def __init__(self): 4 # 原价 5 self.original_price = 100 6 # 折扣 7 self.discount = 0.8 8 9 @property 10 def price(self): 11 # 实际价格 = 原价 * 折扣 12 new_price = self.original_price * self.discount 13 return new_price 14 15 @price.setter # set时候自动运行 16 def price(self, value): 17 self.original_price = value 18 19 @price.deleter # 删除的时候自动运行 20 def price(self): 21 del self.original_price 22 23 24 obj = Goods() 25 obj.price # 获取商品价格 26 obj.price = 200 # 修改商品原价 27 print(obj.price) 28 del obj.price # 删除商品原价
classmethod 类方法
1 class Goods: 2 __discount = 0.8 3 def __init__(self, name, price): 4 self.name = name 5 self.__price = price 6 @property # @property装饰器装饰后,调用该方法后面不用加() 7 def price(self): 8 return self.__price*Goods.__discount 9 10 @classmethod # 把一个方法变成一个类中的方法,这个方法就可以被类调用,不需要依托任何对象 11 def change_discount(cls, new_discount): # 修改折扣 12 cls.__discount = new_discount 13 apple = Goods(‘苹果‘, 5) 14 print(apple.price) # 4.0 15 Goods.change_discount(0.5) 16 print(apple.price) # 2.5 17 # 当这个方法的操作只涉及静态属性的时候,就应该使用classmethod来装饰这个方法
staticmethod方法
class Staticmethod_Demo(): role = ‘dog‘ @staticmethod def func(): print("当普通方法用") Staticmethod_Demo.func() # 在完全面向对象的程序中,如果一个函数既和对象没有关系,也和类没有关系,那么就用staticmethod将这个函数变成一个静态方法
面向对象的进阶
isinstance和issubclass
isinstance 判断类和对象的关系
issubclass 判断子类和父类的关系
hasattr getattr setattr delattr 四个实现自省的函数
1 class Foo: 2 f = ‘类的静态变量‘ 3 def __init__(self,name,age): 4 self.name=name 5 self.age=age 6 7 def say_hi(self): 8 print(‘hi,%s‘%self.name) 9 10 obj=Foo(‘egon‘,73) 11 12 #检测是否含有某属性 13 print(hasattr(obj,‘name‘)) 14 print(hasattr(obj,‘say_hi‘)) 15 16 #获取属性 17 n=getattr(obj,‘name‘) 18 print(n) 19 func=getattr(obj,‘say_hi‘) 20 func() # hi, egon 21 22 #设置属性 23 setattr(obj,‘sb‘,True) 24 setattr(obj,‘show_name‘,lambda self:self.name+‘nb‘) 25 print(obj.__dict__) 26 print(obj.show_name(obj)) # egonnb 27 28 #删除属性 29 delattr(obj,‘age‘) 30 delattr(obj,‘show_name‘) 31 32 注:反射:是用字符串类型的名字 去操作变量
类的内置方法
# __str__ :打印一个对象的时候,就是调用类名.__str__ class Teacher: def __init__(self, name, salary): self.name = name self.salary = salary def __str__(self): return "Teacher‘s object:%s"%self.name def __repr__(self): return str(self.__dict__) nezha = Teacher(‘nezha‘,1200) print(nezha) # Teacher‘s object:nezha print(‘%s‘%nezha) # Teacher‘s object:nezha print(str(nezha)) # Teacher‘s object:nezha print(‘%r‘%nezha) # {‘name‘: ‘nezha‘, ‘salary‘: 1200} print(repr(nezha)) # {‘name‘: ‘nezha‘, ‘salary‘: 1200} # %s str()直接打印 实际上都是走的__str__ # %r repr() 都是走的 __repr__ # 如果没有__str__方法,会先找本类中的__repr__方法,再没有再找父类的__str__ # repr()只会找__repr__,如果没有就找父类
__del__
class Foo: def __del__(self): print(‘执行我啦‘) f1=Foo() del f1 # 执行我啦 # 析构方法,当对象在内存中被释放时,自动触发执行
__call__
对象后面加括号,触发执行。 class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print(‘__call__‘) obj = Foo() # 执行 __init__ obj() # 执行 __call__ 注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
原文:https://www.cnblogs.com/pythoncui/p/12272867.html