Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Einführung in objektorientiert in Python (Codebeispiele)

Detaillierte Einführung in objektorientiert in Python (Codebeispiele)

不言
不言nach vorne
2018-12-13 10:37:482094Durchsuche

Dieser Artikel bietet Ihnen eine detaillierte Einführung in die Objektorientierung in Python (Codebeispiele). Ich hoffe, dass er für Freunde hilfreich ist.

Drei Hauptmerkmale der Objektorientierung: integrierte polymorphe Kapselung
Lassen Sie uns etwas über die Implementierung von drei Funktionen in Python lernen

Vererbung

#继承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 派生类

Vererbung beschreibt die Beziehung zwischen der Unterklasse und der übergeordneten Klasse, eine Was-ist-Beziehung. Um diese Beziehung herauszufinden, müssen Sie zunächst abstrahieren und dann erben.

Abstraktion bedeutet, ähnliche oder ähnlichere Teile zu extrahieren.

Abstraktion ist in zwei Ebenen unterteilt:

1. Extrahieren Sie die ähnlichen Teile von Obama und Messi Teile der drei Kategorien Mensch, Schwein und Hund in übergeordnete Kategorien ein.

Die Hauptaufgabe der Abstraktion besteht darin, Kategorien zu unterteilen (was Bedenken isolieren und die Komplexität reduzieren kann)

Vererbung: Sie basiert auf dem Ergebnis der Abstraktion, Sie muss zuerst die Abstraktion erfahren. Nur durch diesen Prozess können abstrakte Strukturen durch Vererbung ausgedrückt werden.

Abstraktion ist nur eine Aktion oder eine Technik im Prozess der Analyse und des Designs. Durch Abstraktion können wir

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

# 猫和狗有大量相同的内容
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()
Vererbung und Wiederverwendbarkeit

im Prozess der Programmentwicklung erreichen, wenn wir Definieren Sie eine Klasse A und möchten Sie dann eine weitere Klasse B erstellen, aber die meisten Inhalte von Klasse B sind mit denen von Klasse A identisch

Wir können eine Klasse B nicht von Grund auf neu schreiben, daher verwenden wir das Konzept von Klassen Nachlass.

Erstellen Sie eine neue Klasse B durch Vererbung, lassen Sie B A erben, und B „erbt“ alle Attribute von A (Datenattribute und Funktionsattribute), wodurch die Wiederverwendung von Code realisiert wird

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
'''
Tipp: Verwenden Einige Klassen erstellen bereits eine neue Klasse und verwenden so einige Einstellungen in der vorhandenen Software, was den Programmieraufwand erheblich erhöht. Dies wird oft als Software-Wiederverwendung bezeichnet. Sie können nicht nur Ihre eigenen Klassen wiederverwenden, sondern auch andere erben B. die Standardbibliothek zum Anpassen neuer Datentypen, was den Softwareentwicklungszyklus erheblich verkürzt, was für die Softwareentwicklung im großen Maßstab von großer Bedeutung ist.

Die Klassenvererbung ist unterteilt in: Einzelvererbung und Mehrfachvererbung

Bevor wir Einzelvererbung und Mehrfachvererbung lernen, lernen wir hier zunächst die Klassentypen

1. Klassische Klassen (nicht die Objektklasse erben)

2. Klassen neuen Stils (Objektklassen erben)

3. Klassische Klassen von Python2 und Klassen neuen Stils existieren nebeneinander

4.Python3 Alle sind Klassen neuen Stils

Einzelvererbung

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)
Wir verstehen die Syntax der Einzelvererbung: Die Unterklasse hat ihre eigenen Attribute und Methoden Elternklasse und die Attribute und Methoden der Unterklasse?
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列表中的位置的下一个类开始查找动态方法或静态属性


Mehrfachvererbung

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列表
#对于定义的每一个类,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;>]
Um die Vererbung zu implementieren, durchsucht Python die Basisklasse von links nach rechts in der MRO-Liste, bis es die erste passende Klasse findet dieses Attribut Bis zur Klasse. Der Aufbau dieser MRO-Liste wird durch einen C3-Linearisierungsalgorithmus implementiert. Wir werden uns nicht mit den mathematischen Prinzipien dieses Algorithmus befassen. Er führt tatsächlich die MRO-Listen aller übergeordneten Klassen zusammen und folgt den folgenden drei Richtlinien:

Unterklassen werden vor übergeordneten Klassen gefunden

Mehrere übergeordnete Klassen Klassen werden in der Reihenfolge von Platz nach rechts in der Liste nachgeschlagen

Wenn es zwei rechtliche Möglichkeiten für die nächste Klasse gibt, wählen Sie die erste übergeordnete Klasse aus

Abstrakte Klassen und Schnittstellenklasse

Bevor wir abstrakte Klassen verstehen, sprechen wir zunächst über Schnittstellen. Die Schnittstelle bezieht sich hier auf den Methodeneingang, den wir Benutzern zum Aufrufen ihrer eigenen Funktionen bereitstellen.

Warum verwenden wir also Schnittstellen?


Wir extrahieren Funktionen mit ähnlichen Funktionen in einer Gruppe von Klassen, wie z. B. WeChat-Zahlung, Alipay-Zahlung, UnionPay-Zahlung usw. Dies sind alles Zahlungsfunktionen. Wir können diese Funktionen extrahieren und als Klasse definieren Die Implementierung von Funktionen definiert beispielsweise nur die einheitlichen Namen dieser Funktionen. Normalisierung bedeutet, dass die Objekte von allen generiert werden, solange sie auf derselben Schnittstelle basieren Diese Klassen werden verwendet, wenn sie verwendet werden. Die Verwendung ist dieselbe.

Die Vorteile der Normalisierung sind:

1. Durch die Normalisierung müssen sich Benutzer nicht um die Klasse des Objekts kümmern, sondern müssen nur wissen, welche Klasse diese Objekte haben Bestimmte Nur diese Funktionen reichen aus, was die Nutzungsschwierigkeiten für Benutzer erheblich verringert.

2. Durch die Normalisierung können hochrangige externe Benutzer alle schnittstellenkompatiblen Objektsätze wahllos verarbeiten

2.1: Genau wie Linux-Pan-Dateien. Das Konzept ist dasselbe. Alles kann als Datei verarbeitet werden, egal ob Speicher, Festplatte, Netzwerk oder Bildschirm (natürlich können Low-Level-Designer natürlich auch zwischen „Zeichengeräten“ und „Blockgeräten“ unterscheiden). Gezieltes Design erstellen: Wie detailliert es ist, hängt von den Bedürfnissen ab.

2.2: Ein weiteres Beispiel: Wir haben eine Autoschnittstelle, die alle Funktionen des Autos definiert, und dann implementieren die Honda-Autoklasse, die Audi-Autoklasse und die Volkswagen-Klasse alle die Autoschnittstelle , das wird einfach sein. Jeder muss nur lernen, ein Auto zu fahren, und dann können wir es fahren, egal ob es ein Honda, ein Audi oder ein Volkswagen ist Laufwerk oder wie man es bedient (Funktionsaufrufe) sind gleich

#做出一个良好的接口
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)

归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象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()

抽象类和抽象接口

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如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)

鸭子类型

#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")

封装

#广义的封装:将一些内容放到一个"容器"中
#狭义的封装:私有
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

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

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

静态变量

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

对象属性

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

方法:

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

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)  # 类外不可以访问

#总结:

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

#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:自定义触发异常触发异常后,后面的代码就不会再执行

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

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()

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"

为什么要用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()

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())

#小补充

#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"))

对类

class a:
    name = "kom"
    def __init__(self):
        pass
    
    def func(self):
        print("in func")
        
getattr(a,"name")
ret = getattr(a,"func")
print(ret(1))

对当前模块(文件)

import sys
def s1():
    print 's1'


def s2():
    print 's2'

this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')

对其他模块(文件)

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

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

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


a.func2(1)

双下方法

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) {}

设计模式

单例模式

由于类产生实例的过程是通过 __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>

item

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

Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in objektorientiert in Python (Codebeispiele). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen