Introduction détaillée à l'orientation objet en Python (exemples de code)

不言
Libérer: 2018-12-13 10:37:48
avant
2096 Les gens l'ont consulté

Cet article vous apporte une introduction détaillée à l'orientation objet en Python (exemples de code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Trois fonctionnalités majeures de l'orienté objet : l'encapsulation polymorphe intégrée
Apprenons l'implémentation de trois fonctionnalités en Python

Héritage

#继承demo
class Animal:
    def __init__ (self,kind,age,sex):
        self.kind = kind
        self.age = age
        self.sex = sex
class Person(Animal):
    pass
class Dog(Animal):
    pass

class Cat(Animal):
    pass
#Animal:父类 or 基类
#Person:子类 or 派生类
Copier après la connexion

L'héritage décrit la relation entre la sous-classe et la classe parent, une relation de type. Pour découvrir cette relation, vous devez d'abord faire abstraction puis hériter.

L'abstraction signifie extraire des parties similaires ou plus similaires.

L'abstraction est divisée en deux niveaux :

1. Extrayez les parties les plus similaires d'Obama et de Messi en catégories

2. des parties similaires des trois catégories d'humains, de porcs et de chiens dans des catégories parentales.

Le rôle principal de l'abstraction est de diviser les catégories (ce qui peut isoler les préoccupations et réduire la complexité)

Héritage : il est basé sur le résultat de l'abstraction. Pour l'implémenter via un langage de programmation, vous. doit d'abord faire l'expérience de l'abstraction. Ce n'est qu'à travers ce processus que les structures abstraites peuvent s'exprimer par héritage.

L'abstraction n'est qu'une action ou une technique dans le processus d'analyse et de conception. Grâce à l'abstraction, nous pouvons obtenir

# ==========================第一部分
# 例如
# 猫可以:喵喵叫、吃、喝、拉、撒
# 狗可以:汪汪叫、吃、喝、拉、撒
# 如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,伪代码如下:

# 猫和狗有大量相同的内容
class cat:

    def 喵喵叫(self):
        print('喵喵叫')


    def 吃(self):
        print("吃东西")

    def 喝(self):
        print("喝水")

    def 拉(self):
        print("拉了")



class dog:

    def wangwang(self):
        print('旺旺叫')


    def 吃(self):
        print("吃东西")

    def 喝(self):
        print("喝水")

    def 拉(self):
        print("拉了")



#== == == == == == == == == == == == == 第二部分
#上述代码不难看出,吃、喝、拉、撒是猫和狗都具有的功能,而我们却分别的猫和狗的类中编写了两次,如果使用继承的思想,如下实现:
#动物:吃、喝、拉、撒
#猫:喵喵叫(猫继承动物的功能)
#狗:汪汪叫(狗继承动物的功能)

#伪代码如下:

class 动物:

    def 吃(self):
        print("吃东西")

    def 喝(self):
        print("喝水")

    def 拉(self):
        print("拉了")


# do something

# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class cat(动物):
    def 喵喵叫(self):
        print("喵喵叫")


# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class dog(动物):
        def 汪汪叫(self):
            print("汪汪叫")
#== == == == == == == == == == == == == 第三部分


# 继承的代码实现
class Animal:

    def eat(self):
        print("%s 吃 " % self.name)

    def drink(self):
        print("%s 喝 " % self.name)

    def shit(self):
        print("%s 拉 " % self.name)

    def pee(self):
        print("%s 撒 " % self.name)


class Cat(Animal):

    def __init__(self, name):
        self.name = name
        self.breed = '猫'

    def cry(self):
        print('喵喵叫')


class Dog(Animal):

    def __init__(self, name):
        self.name = name
        self.breed = '狗'

    def cry(self):
        print('汪汪叫')


########## 执行 #########

c1 = Cat('小白家的小黑猫')
c1.eat()

c2 = Cat('小黑的小白猫')
c2.drink()

d1 = Dog('胖子家的小瘦狗')
d1.eat()
Copier après la connexion

Héritage et réutilisabilité
Dans le processus de développement de programmes, Si nous définissons une classe A, puis voulons créer une autre classe B, mais que la plupart du contenu de la classe B est le même que celui de la classe A

nous ne pouvons pas écrire une classe B à partir de zéro, alors utilisez Venez au concept d'héritage de classe.

Créez une nouvelle classe B par héritage, laissez B hériter de A et B « héritera » de tous les attributs de A (attributs de données et attributs de fonction), réalisant ainsi la réutilisation du code

class Hero:
    def __init__(self,nickname,aggressivity,life_value):
        self.nickname=nickname
        self.aggressivity=aggressivity
        self.life_value=life_value

    def move_forward(self):
        print('%s move forward' %self.nickname)

    def move_backward(self):
        print('%s move backward' %self.nickname)

    def move_left(self):
        print('%s move forward' %self.nickname)

    def move_right(self):
        print('%s move forward' %self.nickname)

    def attack(self,enemy):
        enemy.life_value-=self.aggressivity
class Garen(Hero):
    pass

class Riven(Hero):
    pass

g1=Garen('草丛伦',100,300)
r1=Riven('锐雯雯',57,200)

print(g1.life_value)
r1.attack(g1)
print(g1.life_value)

'''
运行结果
243
'''
Copier après la connexion

Astuce : Créez une nouvelle classe en utilisant une classe existante, réutilisant ainsi certains paramètres du logiciel existant et augmentant considérablement la charge de travail de programmation. Ceci est souvent appelé réutilisation du logiciel. Non seulement vous pouvez réutiliser vos propres classes, mais vous pouvez également en hériter. les classes d'autres personnes. , comme la bibliothèque standard, pour personnaliser de nouveaux types de données, ce qui raccourcit considérablement le cycle de développement logiciel, ce qui est d'une grande importance pour le développement de logiciels à grande échelle

L'héritage de classe est divisé en : unique ; l'héritage et l'héritage multiple

Avant d'apprendre l'héritage simple et l'héritage multiple, nous apprenons d'abord ici les types de classes

Les classes classiques (n'héritent pas de la classe objet)

2. Classes de nouveau style (hériter de la classe d'objets)

3. Les classes classiques Python2 et les classes de nouveau style coexistent

4. Python3 sont toutes des classes de nouveau style

. 🎜>Héritage unique

class Animal:
    a1 = "测试"
    def __init__(self,kind,age,sex):
        self.kind = kind
        self.age = age
        self.sex = sex
class Person(Animal):
    a1 = "alex"
    pass

class Dog(Animal):
    pass

class Cat(Animal):
    pass

a = Person("人类",18,"男")
print(a.kind)
Copier après la connexion


Nous comprenons la syntaxe de l'héritage unique. Nous avons maintenant une telle exigence :

La sous-classe a ses propres attributs. les attributs et méthodes de la classe parent tout en appelant également les propriétés et méthodes de la sous-classe ?
class Animal:
    def __init__(self,name,sex,age):
        self.name = name
        self.sex = sex
        self.age = age

    def eat(self):
        print("%s正在吃饭" %(self.name))

class Person(Animal):
    def __init__(self,name,sex,age,coat_color):
        #super(Person,self).__init__(name,sex,age) python2写法
        super().__init__(name,sex,age)   #重构父类的__init__并给父类传递需要的参数,super()是一个特殊的对象默认会把self(对象自己)传递给父类当第一个参数(父类的self);
        self.coat_color = coat_color

    def eat(self):
        print("%s人类%s正在吃饭" % (self.coat_color,self.name))
        super().eat()

class Dog(Animal):
    def __init__(self,coat_color):
        self.coat_color = coat_color
        
    def eat(self):
        print("狗狗正在吃饭")

p2 = Person("王铁锤","女",18,"黄色")
p2.eat()
print(Person.__mro__)  #查看类的mro列表
>>>(<class &#39;__main__.Person&#39;>, <class &#39;__main__.Animal&#39;>, <class &#39;object&#39;>)
#super():是一个特殊对象,会按当前类所在mro列表中的位置的下一个类开始查找动态方法或静态属性
Copier après la connexion

Héritage multiple

class Base:
    def __init__(self):
        print('Base.__init__')

class A(Base):
    def __init__(self):
        super().__init__()
        print('A.__init__')

class B(Base):
    def __init__(self):
        super().__init__()
        print('B.__init__')

class C(A,B):
    def __init__(self):
        super().__init__()  # Only one call to super() here
        print('C.__init__')
c = C()
print(C.mro())  #查看可的MON列表
Copier après la connexion
#对于定义的每一个类,Python会计算出一个所谓的方法解析顺序(MRO)列表;这个MRO列表就是一个简单的所有基类的线性顺序表。例如:
print(C.mro())
>>>[<class &#39;__main__.C&#39;>, <class &#39;__main__.A&#39;>, <class &#39;__main__.B&#39;>, <class &#39;__main__.Base&#39;>, <class &#39;object&#39;>]
Copier après la connexion

Pour implémenter l'héritage, Python recherchera la classe de base de gauche à droite dans la liste MRO jusqu'à ce qu'elle se trouve dans la première classe qui correspond à cet attribut.

La construction de cette liste MRO est mise en œuvre grâce à un algorithme de linéarisation C3. Nous n'entrerons pas dans les principes mathématiques de cet algorithme. Il fusionne en fait les listes MRO de toutes les classes parents et suit les trois directives suivantes :

Les sous-classes seront trouvées avant la classe parent

Plusieurs. Les classes parents sont recherchées selon leur ordre du siège vers la droite dans la liste

S'il y a deux choix légaux pour la classe suivante, choisissez la première classe parent

Classes abstraites et interfaces Classe
Avant de comprendre les classes abstraites, parlons d'abord des interfaces. L'interface fait ici référence à : l'entrée de méthode que nous fournissons aux utilisateurs pour appeler leurs propres fonctions

Alors pourquoi utilisons-nous des interfaces ?


Nous extrayons des fonctions avec des fonctions similaires dans un groupe de classes, telles que le paiement WeChat, le paiement Alipay, le paiement UnionPay, etc. Ce sont toutes des fonctions de paiement. Nous pouvons extraire ces fonctions et les définir comme une classe. La classe n'est pas spécifique. L'implémentation des fonctions définit uniquement les noms unifiés de ces fonctions. Par exemple, la signification de ceci est la normalisation, c'est que tant que les classes sont implémentées sur la même interface, alors les objets sont générés par tous. ces classes seront utilisées lorsqu'elles seront utilisées, l'usage est le même.


Les avantages de la normalisation sont :


1. La normalisation permet aux utilisateurs de ne pas avoir à se soucier de la classe de l'objet, mais seulement de savoir que ces objets ont certaines Ces fonctions suffisent, ce qui réduit considérablement la difficulté d'utilisation pour les utilisateurs.


2. La normalisation permet aux utilisateurs externes de haut niveau de traiter sans discernement toutes les collections d'objets compatibles avec l'interface


2.1 : Tout comme les fichiers panoramiques Linux Le concept est le même, tout peut être traité comme un fichier, qu'il s'agisse de mémoire, de disque, de réseau ou d'écran (bien sûr, pour les concepteurs de bas niveau, bien sûr, ils peuvent également faire la distinction entre les "périphériques de caractères" et les "périphériques de bloc", puis réaliser une conception ciblée : son niveau de détail dépend des besoins).


2.2 : Autre exemple : nous avons une interface de voiture, qui définit toutes les fonctions de la voiture, puis la classe de voiture Honda, la classe de voiture Audi et la classe Volkswagen implémentent toutes l'interface de voiture , ce sera facile. Tout le monde a seulement besoin d'apprendre à conduire une voiture, et ensuite nous pourrons la conduire, qu'il s'agisse d'une Honda, d'une Audi ou d'une Volkswagen. Lorsque nous conduisons, nous n'avons pas besoin de nous soucier du type de voiture que nous conduisons. le lecteur ou comment le faire fonctionner (appels de fonction) sont les mêmes

#做出一个良好的接口
class Payment(object):
    #规定了一个兼容接口
    def pay(self):
        pass

#微信支付
class WeChatPay(object):
    def pay(self,money):
        print('微信支付了%s'%money)

#支付宝支付
class AliPay(object):
    def pay(self,money):
        print('支付宝支付了%s'%money)

#苹果支付
class ApplePay(object):
    def pay(self,money):
        print('苹果支付了%s'%money)

def pay(obj,money):
    obj.pay(money)

weixin = WeChatPay()
alipay = AliPay()
applepay = ApplePay()

#调用者无需关心具体实现细节,可以一视同仁的处理实现了特定接口的所有对象
pay(weixin,100)
pay(alipay,200)
pay(applepay,300)
Copier après la connexion

归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)

抽象类

什么是抽象类

与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

为什么要有抽象类

如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案

import abc

class Animal(metaclass=abc.ABCMeta): #metaclass=abc.ABCMeta:元类
    @abc.abstractmethod
    def eat(self):
        pass
    @abc.abstractmethod
    def run(self):
        pass

class People(Animal):
    def eat(self):
        print("pople is eating")
    def run(self):
        print("pople is runing")


a = People()
a.eat()
Copier après la connexion

抽象类和抽象接口

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计

在python中,并没有接口类这种东西,即便不通过专门的模块定义接口,我们也应该有一些基本的概念

多态

Python默认支持多态

多态指的是一类事物有多种形态

动物有多种形态:人,狗,猪
import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print('say aoao')

p1 = People()
d1 = Dog()
p2 = Pig()
p1.talk()
p2.talk()
d1.talk()
#多态性:在不考虑对象具体类型的情况下直接使用对象下的方法,比如列表 字符串 元祖等可以不考虑对象的类型直接调对应的方法,比如上边的代码无论是人或者狗或者猪我们不需要考虑这个类具体的类型因为他们都属于动物类,那么动物类都用talk方法

#我们上边学到了接口的概念那么我们在这里就可以用到将三个雷进行统一化
def talk(obj):
    obj.talk()
talk(p1)
talk(p2)
talk(d1)
Copier après la connexion

鸭子类型

#python推崇的鸭子类型而不是抽象类的概念
#当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子;sqqqqqqcvx b
#在鸭子类型中关注的不是对象的类型本身,而是它是如何使用的;
#在定义类的时候没有必要硬性定义一个父类,比如下面的代码三个类不需要父类,只需要都有发出声音的方法就行,某一个类的增加功能不需要考虑其他类实现了解耦;

import abc
class Pig():
    def speak(self):
        print("哼哼")
        
    
class Dog():
    def speak(self):
        print("汪汪")

class Radio():
    def speak(self):
        print("radio speak")
Copier après la connexion

封装

#广义的封装:将一些内容放到一个"容器"中
#狭义的封装:私有
class test:
    name = "jim"
    __name = "tom" #私有属性
    
    def func(self):  #动态方法
        pass
        
    def __init__(self): #特殊方法
        self.name 
        self.__age = age #私有对象属性
        
    def _func(self): #私有方法
        pass
        
    @property  #属性:将方法伪装成一个属性,虽然在代码层面没有提升,但是会让代码看起来更合理;
    
    def func1(self):
        pass
    @classmethod #类方法(用于对于类的修改)
    def func2(cls):  #cls会接收类名类似self接收对象名一样
        pass
        
    @staticmethod #静态方法:不依赖类与对象的函数,封装在类中用于代码整洁一体化
    def func3():
        pass
Copier après la connexion

私有成员:私有变量 私有对象属性 私有方法

对于每一个类的成员而言都有两种形式:
公有成员,在任何地方都能访问
私有成员,只有在类的内部才能方法
私有成员和公有成员的访问限制不同

静态变量

公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
私有静态字段:仅类内部可以访问;

对象属性

公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问;
私有普通字段:仅类内部可以访问;

方法:

公有方法:对象可以访问;类内部可以访问;派生类中可以访问
私有方法:仅类内部可以访问;

class test:
    name = "jim"     #公有静态属性
    __name = "tom"   #私有静态属性
    
    def __init__(self,): 
        self.name = name #公有对象属性
        self.__age = age #私有对象属性
        
    def _func(self): #私有方法
        pass
    
    def test(self):  #公有方法
        pass
    
class A:
    count = "china"
    __name = "alex"

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def func(self):
        print(self.__name)

    def __fuck(self):
        pass
obj = A("jim", 28)
print(obj.coutry)  # 类外可以访问
print(obj.__name)  # 类外不可以访问
Copier après la connexion

#总结:

#对于这些私有成员来说,他们只能在类的内部使用,不能再类的外部以及派生类中使用.

#ps:非要访问私有成员的话,可以通过 对象._类__属性名,但是绝对不允许!!!

#为什么可以通过._类__私有成员名访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名.

#__开头的属性只是一种语法意义上的变形,并不会真正限制外部访问;

#这种变形只在类定义阶段发生一次,类定义之后再新增的属性不会变形;

封装数据属性的意义:将静态变量或对象变量封装起来以后,对象无法直接使用只能在类中使用这又有什么用呢?

1.将属性封装了以后对象通过统一的类方法(接口)才能增加静态属性,并且根据对象的传值的合法性来决定是否给用户增加静态属性,这就有意义了对于某些特殊的属性我们就需要通过统一的接口才能修改,并且遵循接口的定义者的规范;

class Person:
    def __init__(self):
        pass

    def eat(self):
        print("%s人类%s正在吃饭" % (self.coat_color, self.__name))

    def set_info(self,name,age,sex,coat_color):
        if type(name) is not str:
            raise TabError("name not is str")
        elif type(age) is not int:
            raise TabError("name not is int")
        else:
            self.__name = name
            self.__age = age
            self.__sex = sex
            self.coat_color = coat_color

p = Person()
p.set_info("jim",18,"男人","黄种")
p.eat()
#raise:自定义触发异常触发异常后,后面的代码就不会再执行
Copier après la connexion

封装函数属性的意义:隔离复杂度

1. 电视机本身是一个黑盒子,隐藏了所有细节,但是一定会对外提供了一堆按钮,这些按钮也正是接口的概念,所以说,封装并不是单纯意义的隐藏!!!

2. 快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了

提示:在编程语言里,对外提供的接口(接口可理解为了一个入口),可以是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。

#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
#隔离了复杂度,同时也提升了安全性

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print_bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')

    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()
Copier après la connexion

property

@property:property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

使用场景:对象需要得到一个动态的返回值,并且调用方式与调用数据属性一样的方式调用

class People:
    def __init__(self,name,age,height,weight):
        self.name = name
        self.age = age
        self.height = height
        self.weight = weight
    @property
    def bim(self):
        return self.weight / (self.height ** 2 )

p1 = People("jim",28,1.8,72)
print(p1.bim)       #通过@property装饰的方法改变了调用方式
print(p1.name)      #调用普通的数据属性

class test:
    def __init__(self,name):
        self.__name = name
    @property            #@property:将动态方法封装成数据属性(常用)
    def name(self):
        return self.__name
    @name.setter         #.setter修改属性
    def name(self,obj):
        self.__name = obj

    @name.deleter       #.deleter删除属性
    def name(self):
        del self.__name
a = test("jim")
print(a.name)
a.name="tom"
Copier après la connexion

为什么要用property

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

classmethod

@classmethod:是一个内置的函数,我们了解类里的动态方法是给对象使用的,所以在定义方法时会自动有一个self关键字
这个关键字就是一个普通的位置参数而已,默认对象在调用方法时会自动将对象的内存地址传递给self这样我们就可以调用对象的属性
@classmethod 这个函数就是将一个普通类方法绑定给类使用,这样这个方法就需要通过类调用,而cls这个关键字就会默认接收类的内存地址
下面的方法还是普通的方法,不过是经过@classmethod装饰后,这个普通方法就通过cls这个关键字接收的不是对象的地址而是类的地址而已
还能通过类似cls.name = "tom" 修改类的静态属性
#settings.py
HOST="127.0.0.1"
PORT=3306

#classmethod_mode.py
import settings
class test:
    def __init__(self,host,port):
        self.host = host
        self.port = port

    def test1(self):
        print(self.host,self.port)

    @classmethod
    def test2(cls):
        print(cls)
        return cls(settings.PORT,settings.HOST)

test.test2()
a = test(settings.PORT,settings.HOST)
a.test1()
Copier après la connexion

staticmethod

@staticmethod:将类方法变成一个普通的函数
我们有这么一个核心文件里面是很多类,但这个时候我们需要写一个普通函数实现某个功能
在类外面也可以写一个同样的函数实现功能,但是这样打乱了逻辑关系,也增加了代码的维护难度
那么我们就写在某个公共类里并且通过@staticmethod装饰一下这样类就会知道它只是一个我类里面定义的普通函数
主要是为了代码整洁归类
#settings.py
HOST="127.0.0.1"
PORT=3306

#classmethod_mode.py
import settings
class test:
    def __init__(self,host,port):
        self.host = host
        self.port = port

    def test1(self):
        print(self.host,self.port)

    @staticmethod
    def test2():
        return (settings.PORT,settings.HOST)

print(test.test2())
Copier après la connexion

#小补充

#isinstance:什么是否是什么实例
l = [1,2,3]
print(isinstance(l,list)) #l是不是列表
#issubclass:什么是谁的子类
print(issubclass(b,a) #True
issubclass:判断b是否是b的子类或孙类

反射:通过字符串操作对象(实例化 类 模块)

有一天我们想通过字符串来对实例 类 或者模块进行某些操作,比如我们通过input()接收的用户输入的信息
这个信息默认是字符串格式,那么我们拿到了这个字符串能通过它来调用对象的属性或类的方法呢?
当然可以这就是反射 把某个字符串反射到某个对象属性或类方法的内存地址上去
反射一共有四个内置函数,可以操作实例化对象 类 模块;
  • hasattr():查找

  • getattr():获取

  • setattr():修改

  • delattr():删除

对实例化对象的示例

class a:
    def __init__(self,name,age):
        self.name = name
        self.age = age

obj = a("jim",28)

ret = getattr(obj,"name",None)
print(ret)

print(hasattr(obj,"name"))

if hasattr(obj,name):
    ret = getattr(obj,"name",None)

setattr(obj,"sex","男")
print(getattr(obj,"sex"))
Copier après la connexion

对类

class a:
    name = "kom"
    def __init__(self):
        pass
    
    def func(self):
        print("in func")
        
getattr(a,"name")
ret = getattr(a,"func")
print(ret(1))
Copier après la connexion

对当前模块(文件)

import sys
def s1():
    print 's1'


def s2():
    print 's2'

this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')
Copier après la connexion

对其他模块(文件)

import fs
print(getattr(fs,"n1"))

#方法1
a = getattr(fs,"A")
print(a.name)

#方法2
print(getattr(fs.A,"name"))


a.func2(1)
Copier après la connexion

双下方法

class test:
    def __init__(self,name,age)
        self.name = name
        self.age = age
    
    def __str__(self):  #__str__方法:在打印对象时默认返回出该方法的返回值(只能是字符串,可以是格式化后的字符串)
        return "%s,%s" %(self.name,self,age)

    def __repr__(self):  #__repr__方法:在repr(对象)时默认输出该方法的返回值
        return "太白"

a = test("jim",27)
print(a)   

class Foo:
    def __init__(self):
        pass

    def __call__(self, *args, **kwargs): #__call__:对象()自动触发__call__() 方法
    print("__call__")


obj = Foo()
obj()  # 对象()自动触发__call__()方法

#__del__方法:当内存中释放时自动触发,主要用于主动关闭mysql连接或关闭文件等操作;

#__init__方法:负责对象的初始化,在初始化前对象已经产生
#__new__方法:属于新式类里的方法,第一个参数是(cls),该方法在实例化的时候会自动调用用于创建对象,并将返回值返回给__init__方法的self参数;

#模拟重构__new__方法
class test:
    def __init__(self):
        print("is init")

    def __new__(cls, *args, **kwargs):  #__new__:对象的产生者
        print("is new")
        #super().__new__(cls)
        return object.__new__(cls)
a = test()


class test2:
    def __init__(self):
        print("__init__ ")
        print(self)
        super(A, self).__init__()

    def __new__(cls):
        print("__new__ ")
        self = super(A, cls).__new__(cls)
        print(self)
        return self
#输出
__new__ 
<__main__.A object at 0x1046c4a20>
__init__ 
<__main__.A object at 0x1046c4a20>
#从输出结果来看,__new__ 方法的返回值就是类的实例对象,这个实例对象会传递给 __init__ 方法中的self参数,以便实例对象可以被正确地初始化;


#__init__方法中除了self之外定义的参数,都将与__new__方法中除cls参数之外的参数是必须保持一致
class B:
    def __init__(self, *args, **kwargs):
        print("init", args, kwargs)

    def __new__(cls, *args, **kwargs):
        print("new", args, kwargs)
        return super().__new__(cls)

B(1, 2, 3)
# 输出
new (1, 2, 3) {}
init (1, 2, 3) {}
Copier après la connexion

设计模式

单例模式

由于类产生实例的过程是通过 __new__ 方法来控制的,因此重写该方法来单例模式是非常方便的;
每次初始化都返回同一个实例,所以两次初始化得到的对象的内存地址应该是一样的
class a:
    __instance = None
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            obj = object.__new__(cls)
            cls.__instance = obj
        return cls.__instance

cc = a()
bb = a()
print(cc,bb)
#输出
<__main__.a object at 0x105513898> <__main__.a object at 0x105513898>
Copier après la connexion

item

#对一个对象进行类似字典的操作,就会触发__item__的某个方法
__getitem__
__setitem__
__delitem__
Copier après la connexion
输出

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal