什么是面向对象?
其实,对于吃饭这件事儿,就可以分为面向过程吃饭和面向对象吃饭。自己亲自下厨就是面向过程,点外卖就是面向对象。
一、面向对象的四大方法:静态方法,类方法,属性方法,魔法方法
-
静态方法
-
作用:静态方法可以更好的组织代码,防止代码变大后变得比较混乱。
-
特性: 静态方法只是名义上归类管理,实际上在静态方法里访问不了类或则实例中的任何属性
-
静态方法使用场景:
1)我们要写一个只在类中运行而不在实例中运行的方法.
2)经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法.
3)比如更改环境变量或者修改其他类的属性等能用到静态方法.
4)这种情况可以直接用函数解决, 但这样同样会扩散类内部的代码,造成维护困难.- 调用方式: 既可以被类直接调用,也可以通过实例调用
-
class Dog(object):
def __init__(self,name):
self.name = name
@staticmethod
def eat():
print("I am a static method")
d = Dog("ChenRonghua")
d.eat() #方法1:使用实例调用
Dog.eat() #方法2:使用类直接调用
-
类方法
-
作用:无需实例化直接被类调用
-
特性: 类方法只能访问类变量,不能访问实例变量
-
类方法使用场景: 当我们还未创建实例,但是需要调用类中的方法
-
调用方式: 既可以被类直接调用,也可以通过实例调用
-
class Dog(object):
name = '类变量' #在这里如果不定义类变量仅定义实例变量依然报错
def __init__(self,name):
self.name = '实例变量'
self.name = name
@classmethod
def eat(self,food):
print("%s is eating %s"%(self.name,food))
Dog.eat('baozi') #方法1:使用类直接调用
d = Dog("ChenRonghua")
d.eat("包子") #方法2:使用实例d调用
-
属性方法
- 作用:属性方法把一个方法变成一个属性,隐藏了实现细节,调用时不必加括号直接d.eat即可调用self.eat()方法
# 例1 : @property
class Dog(object):
def __init__(self, name):
self.name = name
@property
def eat(self):
print(" %s is eating" % self.name)
d = Dog("ChenRonghua")
d.eat()
# 调用会出以下错误, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了,
# 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了
# 例2 :航空公司具体实例
class Flight(object):
def __init__(self,name):
self.flight_name = name
def checking_status(self):
print("checking flight %s status " % self.flight_name)
return 1
@property
def flight_status(self):
status = self.checking_status()
if status == 0 :
print("flight got canceled...")
elif status == 1 :
print("flight is arrived...")
elif status == 2:
print("flight has departured already...")
else:
print("cannot confirm the flight status...,please check later")
f = Flight("CA980")
f.flight_status
-
魔法方法
-
单例模式原理及作用
-
=单例模式:永远用一个对象得实例,避免新建太多实例浪费资源
-
实质:使用__new__方法新建类对象时先判断是否已经建立过,如果建过就使用已有的对象
-
使用场景:如果每个对象内部封装的值都相同就可以用单例模式
-
-
创建单例模式举例
-
class Foo(object):
instance = None
def __init__(self):
self.name = 'alex'
def __new__(cls, *args, **kwargs):
if Foo.instance:
return Foo.instance
else:
Foo.instance = object.__new__(cls,*args,**kwargs)
return Foo.instance
obj1 = Foo() # obj1和obj2获取的就是__new__方法返回的内容
obj2 = Foo()
print(obj1,obj2) # 运行结果: <__main__.Foo object at 0x00D3B450> <__main__.Foo object at 0x00D3B450>
# 运行结果说明:
# 这可以看到我们新建的两个Foo()对象内存地址相同,说明使用的•同一个类,没有重复建立类
-
type生成类调用顺序
-
new : 先于__init__方法,每生成一个实例执行一次
-
init : __init__方法每生成一个实例对象就会执行一次
-
call : 后与__init__方法,C()() 使用类再加一个括号调用, C为类名称
-
del : 析构方法,删除无用的内存对象(当程序结束会自动自行析构方法)
-
@TOC
-
Encapsulation 封装(隐藏实现细节)
-
在类中对数据的赋值、内部调用对外部用户是透明的
-
这使类变成了一个胶囊或容器,里面包含着类的数据和方法
-
作用:
1)防止数据被随意修改
2)使外部程序不需要关注对象内部的构造,只需要通过对外提供的接口进行直接访问
-
-
新式类深度优先、经典类广度优先
-
Inheritance 继承(代码重用)
-
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
-
比如CS中的警察和恐怖分子,可以将两个角色的相同点写到一个父类中,然后同时去继承它
-
使用经典类: Person.init(self,name,age) 并重写写父类Person的构造方法,实现,先覆盖,再继承,再重构
-
# 黑人BlackPerson,白人WhitePerson都去继承父类Person
class Person(object):
def __init__(self,name,age): #执行Person.__init__(self,name,age)时就会将传入的参数执行一遍
self.name = name #所以在BlackPerson中不仅有name,age而且还有sex
self.age = age
self.sex = "normal"
def talk(self):
print("person is talking....")
class WhitePerson(Person):
pass
class BlackPerson(Person):
def __init__(self,name,age,strength): #先覆盖,再继承,再重构
#先覆盖父类的__init__方法,再继承父类__init__,再加自己的参数
Person.__init__(self,name,age) #先继承父类Person,这里self就是BlackPerson本身
#先将name,age传给子类BlackPerson,然后调用Person.__init__构造方法将参数出入父类()
self.strength = strength #然后再重构自己的方法,即写自己的参数
print(self.name,self.age,self.sex)
print(self.strength)
def talk(self):
print("black balabla")
def walk(self):
print("is walking....")
b = BlackPerson("wei er smith",22,"Strong")
b.talk()
b.walk()
# 运行结果:
# wei er smith 22 normal
# Strong
# black balabla
# is walking....
# person is talking....
-
Polymorphism 多态(接口重用)
-
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”
-
指一个基类中派生出了不同的子类,且每个子类在继承同样的方法名的同时又对父类的方法做了不同的实现
-
这就是同一种事物表现出的多种形态
-
比如黄种人继承了人talk这个功能,但是他说的是中文,而美国人的talk是英文,但是他们是同样的talk
-
作用:简单的讲就是允许父类调用子类的方法
-
多态举例
-
class Animal:
def __init__(self, name): # Constructor of the class
self.name = name
def talk(self): # Abstract method, defined by convention only
raise NotImplementedError("Subclass must implement abstract method")
class Cat(Animal):
def talk(self):
return 'Meow!'
class Dog(Animal):
def talk(self):
return 'Woof! Woof!'
animals = [Cat('Missy'),
Dog('Lassie')]
for animal in animals:
print(animal.name + ': ' + animal.talk())
# 运行结果:
# Missy: Meow!
# Lassie: Woof! Woof!
三、面向对象的公有属性,普通属性,私有属性
-
公有属性,普通属性,私有属性 比较
-
公有属性:在内存中仅存一份
-
普通属性:每个实例对象在内存存一份
-
私有属性:实例在外部无法调用
-
-
类中函数私有化
-
默认情况下,程序可以从外部访问一个对象的特性
-
为了让方法和特性变成私有(从外部无法访问),只要在它的名字前加上双下划线即可
-
先在__inaccessible从外界是无法访问的,而在内部还能使用(比如从accessible访问)
-
class Secretive:
def __accessible(self):
print("you can't see me,unless you're calling internally")
def accessible(self):
print("The secret message is:")
self.__accessible()
s = Secretive()
s.accessible()
# 运行结果:
# The secret message is:
# you can't see me,unless you're calling internally
四、反射
- hasattr(ogj,name_str) 判断一个对象里是否有对应的字符串方法
class Dog(object):
def eat(self,food):
print("eat method!!!")
d = Dog()
#hasattr判断对象d是否有eat方法,有返回True,没有返回False
print(hasattr(d,'eat')) #True
print(hasattr(d,'cat')) #False
- getattr(obj,name_str) 根据字符串去获取obj对象里的对应的方法对应的内存地址
class Dog(object):
def eat(self):
print("eat method!!!")
d = Dog()
if hasattr(d,'eat'): # hasattr判断实例是否有eat方法
func = getattr(d, 'eat') # getattr获取实例d的eat方法内存地址
func() # 执行实例d的eat方法
#运行结果: eat method!!!
- 使用stattr给类实例对象动态添加一个新的方法
- 使用stattr给类实例对象动态添加一个新的方法
class Dog(object):
def eat(self,food):
print("eat method!!!")
d = Dog()
def bulk(self): #给Dog类添加一个方法必须先写这个方法
print('bulk method add to Dog obj')
d = Dog()
setattr(d,"bulk",bulk) #将bulk方法添加到实例d中,命名为talk方法
d.bulk(d) #实例d调用刚刚添加的talk方法时必须将实例d自身当变量传入,因为他不会自己传入self
#1. 注:setattr(x,’y’,z)用法: x就是实例对象 y就是在实例中调用时用的名字,z就是改变属性的值/或则要添加的函数的名字(正真的函数)
#2. setattr( 具体实例名称 , ’在类中调用时使用的名称’ , 要添加的真实函数的名称)
#3. 作用: setattr(d,"bulk",bulk) 将bulk方法添加到实例d中并且在实例中以bulk名称调用
- 使用starrt给类实例对象动态添加一个新的方法
class Dog(object):
def __init__(self,name):
self.name = name
def eat(self,food):
print("eat method!!!")
d = Dog('Fly')
#1 实例d中没有sex这个属性,就会动态添加一个属性 sex = Male
setattr(d,"sex",'Male') #给实例d添加一个属性:sex=Male
print("将实例d添加一个新属性sex=Male:\t",d.sex)
#2 如果实例d中本身存在这个属性那么 新的值就会覆盖这个属性
setattr(d,'name','name change to jack')
print("原本名字是Fly改变后的名字是:\t",d.name)
# 运行结果:
# 将实例d添加一个新属性sex=Male: Male
# 原本名字是Fly改变后的名字是: name change to jack
- delattr删除实例属性
class Dog(object):
def __init__(self,name):
self.name = name
def eat(self,food):
print("%s is eating....."%self.name)
d = Dog("NiuHanYang")
choice = input(">>:").strip()
if hasattr(d,choice):
delattr(d,choice) #使用delattr(d,choice)删除实例的属性那么所以下面打印就会报错
print(d.name)
# 运行结果:
# >>:name #输入的值是name
# 下面是报错信息
# Traceback (most recent call last):
# File "C:/Users/admin/PycharmProjects/s14/Day7/test1.py", line 10, in <module>