python基础之面向对象&静态方法&类方法&属性方法&魔法方法以及 反射,封装,继承(新式类 与 经典类),多态,

一. 面向对象编程主要优点

1、面向对象编程主要优点:易维护,易扩展,效率高

  • 其实OOP编程的主要作用和函数一样也是使你的代码修改和扩展变的更容易
  • 函数编程与OOP的主要区别就是OOP可以使程序更加容易扩展和易更改。
  • OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述
  • 使用面向对象编程的原因一方面是因为它可以使程序维护和扩展变得更简单,并且可以大大提高程序开发效率
  • 另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。

2. Class 类(模板)

  • 一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。
  • 在类中定义了这些对象的都具备的属性(variables(data))、共同的方法

3、Object 对象(实例)

  • 一个对象即是一个类的实例化后实例
  • 一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性
  • 就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同

4、类中的一些名词

1.  __init__                                         # 构造函数

2.  Self.name = name                                 # 实例变量、普通属性  或者叫  普通字段

3.  public_object = "public"                       # 类变量、公有属性  或则叫   静态字段

4.  self.__heart= "Normal"                         # 私有属性 在外面无法访问

5.  def shot(self)                                 # 类方法
class Role(object):                    #1、在定义类时继承object就是新式类,没有就是就是旧类式
    public_object = "public"           #2、在类例定义一个公有属性:所有实例都能访问的属性叫“公有属性”
    def __init__(self,name,role,weapon,life_value=100,money=15000):  #构造函数==初始化方法:模板
        self.name = name               #3、普通属性
        self.__heart= "Normal"         #4、私有属性在外面无法访问
    def shot(self):                    #5、类的方法
        print("%s is shooting..."%self.name)

更详细代码在这里:

class Role(object):    #在定义类时继承object就是新式类,没有就是就是旧类式
    public_object = "public"   #在类例定义一个公有属性:所有实例都能访问的属性叫“公有属性”
    def __init__(self,name,role,weapon,life_value=100,money=15000):  #构造函数==初始化方法:模板
        self.name = name    #普通属性
        self.role = role
        self.weapon = weapon
        self.life_value = life_value
        self.money = money
        self.__heart= "Normal"    #私有属性在外面无法访问
    def shot(self):     #类的方法
        print("%s is shooting..."%self.name)
    def got_shot(self):
        print("ah...,I got shot...")
    def buy_gun(self,gun_name):
        print("%s just bought %s" %(self.name,gun_name))
        self.weapon = gun_name          #在购买后让实例值改变

#在下面实例化其实就是传入: Role('r1','Alex','police','AK47') 把r1传给了self
#r1就是实例化后产生的当前Role类的实例,所以self就是实例本身
#我理解r1其实就是__init__函数的内存地址
#所以在下面函数中调用self.name就相当于调用r1.name所以可以调用
r1 = Role('Alex','police','AK47') #生成一个角色  只要一实例化就会自动调用__init__
r2 = Role('Jack','terrorist','B22')  #生成一个角色

r1.shot()
print(r2.weapon)        #在调用r2.buy_gun('AK47')前是:B22
r2.buy_gun('AK47')
print(r2.weapon)        #在调用r2.buy_gun('AK47')后是:AK47

#私有属性
# print(r2.__heart)     #这里的.__heart是私有属性,所以在外部无法访问
print(r2._Role__heart)  #强制访问私有属性的方法

#公有属性
print(r2.public_object) #打印出类的公有属性
Role.public_object = 'change_public'    #从全局改变类的公有属性 r1,r2的公有属性都会变
print(r2.public_object)  #这里打印可以看出公有属性变成类“change_public"
r2.public_object = "public_r2"          #改变r2对象的公有属性,r1不会变
print(r2.public_object)                  #打印出改变后的r2公有属性

5、公有属性,普通属性,私有属性 比较

  • 公有属性:在内存中仅存一份
  • 普通属性:每个实例对象在内存存一份
  • 私有属性:实例在外部无法调用

6、类中函数私有化

  • 1)默认情况下,程序可以从外部访问一个对象的特性

  • 2)为了让方法和特性变成私有(从外部无法访问),只要在它的名字前加上双下划线即可

  • 3)先在__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

二. 面向对象三大特性: 封装,继承,多态

1、Encapsulation 封装(隐藏实现细节)

对类中属性和方法进行一种封装,隐藏了实现细节

  • 在类中对数据的赋值、内部调用对外部用户是透明的
  • 这使类变成了一个胶囊或容器,里面包含着类的数据和方法
  • 作用:
    • 1)防止数据被随意修改
    • 2)使外部程序不需要关注对象内部的构造,只需要通过对外提供的接口进行直接访问

2、 Inheritance 继承(代码重用)

子类继承父类后,就具有了父类的所有属性和方法,先继承,后重写
新式类深度优先、经典类广度优先

  • 一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
  • 比如CS中的警察和恐怖分子,可以将两个角色的相同点写到一个父类中,然后同时去继承它
  • 使用经典类: Person.init(self,name,age)
    并重写写父类Person的构造方法,实现,先覆盖,再继承,再重构

黑人,白人都继承父类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....

3、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!

4.新式类 与 经典类 及 重写构造方法 区别举例

1、 新式类和经典类区别(三种)

- pythn3无论新式类还是经典类都是用 广度优先

- python2中,新式类:广度优先,经典类:深度优先

1)首先,写法不一样:

        class A:                       #经典类写法

          pass

        class B(object):          #新式类写法

          pass

  • 2)多继承中,新式类采用广度优先搜索,而旧式类是采用深度优先搜索,python3中全是广度查询
  • 3)在继承中新式类和经典类写法区别

SchoolMember.init(self,name,age,sex) #经典类写法
super(Teacher,self).init(name,age,sex) #新式类写法

在这里插入图片描述

2、重写特殊的构造方法

注:如果一个类的构造方法被重写,那么就需要调用超类的构造方法,否则对象可能不能给被正确的初始化

其实调用超类构造方法很容易,SongBird类中只添加一行代码

  • 经典类写法: Bird.init(self)
  • 新式类写法: super(SongBird,self).init()

如果将下面代码没有2中的那句调用父类Bird中的self.hungry方法会报错

if self.hungry == True:

AttributeError: SongBird instance has no attribute 'hungry'

例1: 新式类,经典类,无超类构造方法报错:

class Bird:
    def __init__(self):
        self.hungry = True
    def eat(self):
        if self.hungry == True:
            print("Aaaah...")
            self.hungry = False
        else:
            print("no, thanks")
a = Bird()
a.eat()
a.eat()

class SongBird(Bird):
    def __init__(self):
        # Bird.__init__(self)                            # 经典类写法
        # super(SongBird,self).__init__()            # 新式类写法
        self.sound = 'Squawk'
    def sing(self):
        print(self.sound)
b = SongBird()
b.sing()
b.eat()

例2: 模拟学校角色,讲师,学生:

class SchoolMember(object):
    '''学校成员基类'''
    member = 0
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
        self.enroll()       #只要一实例化就自动注册
    def enroll(self):
        '''注册'''
        print("just enrolled a new school member [%s]"%self.name)
        SchoolMember.member += 1
    def tell(self):
        print("------info:%s-------"%self.name)
        for k,v in self.__dict__.items():
            print("\t",k,':',v)
    def __del__(self):        #'''析构方法'''
        print("开除了[%s]...."%self.name)
        SchoolMember.member -= 1
class Teacher(SchoolMember):
    def __init__(self,name,age,sex,salary,course):
        SchoolMember.__init__(self,name,age,sex)           #经典类写法
    #super(Teacher,self).__init__(name,age,sex)        #新式类写法
        self.salary = salary
        self.cource = course
        # self.enroll()
    def teaching(self):
        print("Teacher [%s] is teachin g [%s]"%(self.name,self.cource))
class Student(SchoolMember):
    def __init__(self,name,age,sex,course,tuition):
        SchoolMember.__init__(self,name,age,sex)
        self.cource = course
        self.tuition = tuition
        self.amount = 0
        # self.enroll()
    def pay_tuition(self,amount):
        print("student [%s] has just paied [%s]"%(self.name,amount))
        self.amount += amount
t1 = Teacher("Wusir",28,"F*M",3000,"python")
s1 = Student("HaiTao",38,"M","PYS15",300000)
s2 = Student("Lichuang",12,"M","PYS15",11000)
print(SchoolMember.member)
del s2
print(SchoolMember.member)
t1.tell()

三. 静态方法、类方法、属性方法

1、静态方法

  • 作用:静态方法可以更好的组织代码,防止代码变大后变得比较混乱。
  • 特性: 静态方法只是名义上归类管理,实际上在静态方法里访问不了类或则实例中的任何属性
  • 静态方法使用场景:
    • 1)我们要写一个只在类中运行而不在实例中运行的方法.
    • 2)经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法.
    • 3)比如更改环境变量或者修改其他类的属性等能用到静态方法.
    • 4)这种情况可以直接用函数解决, 但这样同样会扩散类内部的代码,造成维护困难.
  • 调用方式: 既可以被类直接调用,也可以通过实例调用

@staticmethod静态方法:

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:使用类直接调用

2、类方法

  • 作用:无需实例化直接被类调用

  • 特性: 类方法只能访问类变量,不能访问实例变量

  • 类方法使用场景: 当我们还未创建实例,但是需要调用类中的方法

  • 调用方式: 既可以被类直接调用,也可以通过实例调用

@classmethod类方法:

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调用

3、属性方法

作用:属性方法把一个方法变成一个属性,隐藏了实现细节,调用时不必加括号直接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

四. Python中的魔法方法

  • 魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python所调用,你可以定义自己想要的行为,而这一切都是自动发生的。它们经常是两个下划线包围来命名的(比如 initlt),Python的魔法方法是非常强大的,所以了解其使用方法也变得尤为重要!

1.init(self[, …]),new(cls[, …]),del(self)

  • init 构造器,当一个实例被创建的时候初始化的方法。但是它并不是实例化调用的第一个方法,__new__才是实例化对象调用的第一个方法,它只取下cls参数,并把其他参数传给 init。__new__很少使用,但是也有它适合的场景,尤其是当类继承自一个像元组或者字符串这样不经常改变的类型的时候。

new:

1. __new__ 是在一个对象实例化的时候所调用的第一个方法
2. 它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法
3. __new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用
4. __new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string
5. __new__ return的是一个构建的实例

init:

构造器,当一个实例对象被定义时调用

del:

析构器,当删除一个实例对象时调用

五. 反射: hasattr、getattr、setattr 和 delattr

1.hasattr(ogj,name_str) 判断一个对象里是否有对应的字符串方法

hasattr判断对象是否有某方法,返回True或False:

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

2 .getattr(obj,name_str) 根据字符串去获取obj对象里的对应的方法对应的内存地址

getattr获取对象方法内存地址:

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!!!

3. 使用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名称调用

使用stattr给类实例对象动态添加一个新的属性:

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

4. delattr删除实例属性

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>

六. 单例模式讲解

1、单例模式原理及作用

  • 单例模式:永远用一个对象得实例,避免新建太多实例浪费资源
  • 实质:使用__new__方法新建类对象时先判断是否已经建立过,如果建过就使用已有的对象
  • 使用场景:如果每个对象内部封装的值都相同就可以用单例模式

2、创建单例模式举例

创建单例模式举例:

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()对象内存地址相同,说明使用的•同一个类,没有重复建立类
发布了46 篇原创文章 · 获赞 10 · 访问量 1836

猜你喜欢

转载自blog.csdn.net/longlong6682/article/details/104772381
今日推荐