Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erläuterung der dynamischen Eigenschaften und Merkmale in Python_python

Detaillierte Erläuterung der dynamischen Eigenschaften und Merkmale in Python_python

不言
不言Original
2018-04-08 10:45:251411Durchsuche

Dieser Artikel stellt hauptsächlich die detaillierte Erklärung dynamischer Eigenschaften und Funktionen in Python vor. Der Herausgeber findet ihn recht gut, daher werde ich ihn jetzt mit Ihnen teilen und als Referenz verwenden. Kommen Sie und werfen Sie einen Blick mit dem Herausgeber

Einleitung: Dieser Artikel dokumentiert meine wichtigsten Kenntnisse und persönlichen Erfahrungen beim Erlernen der Grundlagen der Metaprogrammierung in Python. Freunde, die planen, mit Python zu beginnen, können vorbeikommen und gemeinsam lernen und kommunizieren.

1. Verwenden Sie dynamische Attribute, um JSON-Datenquellen zu verarbeiten

Attribute: In Python Datenattribute und Methoden zur gemeinsamen Verarbeitung von Daten sogenannte Attribute.

Metaprogrammierung: Programmierung mit Metaklassen, Metaklasse → Klasse → Objekt. Metaklassen sind abstrakter als Klassen und erzeugen Klassen von Klassen.

1. Verwenden Sie dynamische Attribute, um auf JSON-Daten zuzugreifen

Erste Ausgabe: Verwenden Sie json.load(fp), um Daten zu überprüfen

from urllib.request import urlopen
import warnings
import os
import json

URL = 'http://www.oreilly.com/pub/sc/osconfeed'
JSON = 'data/osconfeed.json'

def load():
  if not os.path.exists(JSON):
    msg = 'downloading {} to {}'.format(URL, JSON)
    warnings.warn(msg) #如果需要下载就发出提醒。
    with urlopen(URL) as remote, open(JSON, 'wb') as local: #在with语句中使用两个上下文管理器分别用于读取和保存远程文件。
      local.write(remote.read())
  with open(JSON) as fp:
    return json.load(fp)#json.load函数解析JSON文件,返回Python原生对象。

Zweite Ausgabe: Verwenden Sie dynamische Attribute, um auf JSON-Daten zuzugreifen

Das Format der ersten Ausgabe zum Anzeigen tiefer Daten ist relativ ausführlich, z. B. Feed „Zeitplan“. 40, Wir hoffen, dass Methoden wie „feed.Schedule.events[40].name“ verwendet werden können, um die Leseeigenschaften zu verbessern. Und die zweite Version der Klasse kann rekursiv sein und verschachtelte Karten und Listen automatisch verarbeiten.

from collections import abc

class FronenJSON():
  def __init__(self,mapping):
    self.__data=dict(mapping)#创建副本,同时确保处理的是字典。
    
  def __getattr__(self, name):#仅当没有指定名称的属性才调用__getattr__方法。
    if hasattr(self,name):
      return getattr(self.__data,name)
    else:
      return FronenJSON.build(self.__data[name])
  
  @classmethod  
  def __build__(cls,obj):
    if isinstance(obj,abc.Mapping):#判断obj是否是映射。
      return cls(obj)#创建FrozenJSON对象。
    elif isinstance(obj,abc.MutableSequence):
      return [cls.build(item) for item in obj]#递归调用.build()方法,构建一个列表。
    else:#既不是字典也不是列表,则返回元素本身。
      return obj

Analyse: Der Schlüssel zur FronenJSON-Klasse ist die Methode __getattr__. Der Interpreter ruft die spezielle Methode __getattr__ nur auf, wenn das Attribut nicht mit herkömmlichen Mitteln abgerufen werden kann (d. h. das angegebene Attribut kann in der Instanz, Klasse oder Oberklasse nicht gefunden werden).

2. Umgang mit ungültigen Attributnamen

Da in Python Schlüsselwörter reserviert sind, sind Attribute mit dem Namen Schlüsselwörter ungültig. Daher ist es notwendig, __init__ in der zweiten Version zu verbessern:

  def __init__(self,mapping):
    self.__data={}
    for key,value in mapping.items():
      if keyword.iskeyword(key):
        key+='_'#与Python关键字重复的key在尾部加上下划线。
      self.__data[key]=value

3. Verwenden Sie die spezielle Methode __new__

Dritte Ausgabe: Verwenden Sie den Konstruktor __new__, um eine Klasse in eine flexible Objektfabrikfunktion umzuwandeln.

from collections import abc

class FronenJSON():
  def __new__(cls, arg): # __new__是类方法,第一个参数是类本身cls。
    if isinstance(arg, abc.Mapping):
      return super().__new__(cls) #委托给超类object基类的__new__方法处理。
    elif isinstance(arg, abc.MutableSequence): # 余下方法与原先的build方法一致。
      return [cls(item) for item in arg]
    else:
      return arg
 
   def __init__(self,mapping):
    self.__data={}
    for key,value in mapping.items():
      if keyword.iskeyword(key):
        key+='_'
      self.__data[key]=value 

  def __getattr__(self, name):
    if hasattr(self,name):
      return getattr(self.__data,name)
    else:
      return FronenJSON(self.__data[name])

2. Funktionen

1. Klassenattribute, Instanzattribute, private Attribute und Merkmale

Klassenattribute: Klassenattribute werden außerhalb von __init__() initialisiert und gehören zur Klasse. Alle Instanzen haben ein gemeinsames Attribut.
Aufrufmethode: Klassenattribute werden intern mit dem Attributnamen „classname.class“ aufgerufen und können extern entweder mit dem Attributnamen „classname.class“ oder dem Attributnamen „instancename.class“ aufgerufen werden.

Instanzattribute: Instanzattribute gehören zu jeder Instanz und beeinträchtigen sich nicht gegenseitig.

Private Attribute:

  1. Beginnt mit einem einzelnen Unterstrich _: Es zeigt anderen nur an, dass es sich um ein privates Attribut handelt und auf externe Änderungen weiterhin zugegriffen werden kann.

  2. Doppelter Unterstrich __ beginnt mit: Die Außenseite kann nicht über Instanzenname.Eigenschaftsname darauf zugreifen oder es ändern. Es wird tatsächlich in _Klassenname__Eigenschaftsname umgewandelt.

Attribut: Es handelt sich um ein Klassenattribut, das zum Verwalten von Instanzattributen verwendet wird.
Funktionsnutzung: Wird häufig verwendet, um öffentliche Eigenschaften in Eigenschaften umzuwandeln, die mithilfe von Lese- und Set-Methoden verwaltet werden, und um Geschäftsregeln zu implementieren, ohne den Clientcode zu beeinträchtigen.

Hinweis:

  1. Verwenden Sie nicht denselben Namen für Instanzeigenschaften und Klasseneigenschaften. Andernfalls überdecken Instanzattribute Klassenattribute, was zu schwer zu findenden Fehlern führt.

  2. Instanzattribute überschatten keine Klassenattribute, aber Klassenattribute überschatten Instanzattribute.

Das liegt daran, dass obj.attr nicht ausgehend von der Instanz obj nach attr sucht, sondern von obj.__class__, und zwar nur, wenn es in der Klasse kein Attribut mit dem Namen attr gibt, Python Nur dann Wird das Attribut in der Instanz gefunden?

Kurz gesagt, was die Schattenebene betrifft, sind Klasseneigenschaften > Instanzeigenschaften > Klasseneigenschaften.

2. Verwenden Sie Merkmale, um Attribute zu überprüfen.

Durch die Verwendung von Merkmalen können Sie die Gültigkeit von Instanzattributen überprüfen und andere Attribute basierend auf bekannten Attributen und Beziehungen zwischen Attributen anpassen Codierung.
Angenommen, ein Geschäft verkauft eine Vielzahl von Bio-Lebensmitteln wie Nüssen und Getreide. Die Bestellung jedes Kunden umfasst eine Reihe von Produkten im Geschäft. Wir müssen den Gesamtpreis auf der Grundlage der Bestellung des Kunden berechnen.

Analyse: Wir möchten nicht, dass das Gewicht des vom Kunden bestellten Produkts eine nicht positive Zahl ist. Wir müssen den @property-Dekorator verwenden, um den Wert zu erhalten und festzulegen, um die Gültigkeit zu überprüfen der Instanzattribute. Der Code lautet wie folgt:

class LineItem():
  def __init__(self,description,weight,price):
    self.description=description
    self.weight=weight
    self.price=price

  def subtotal(self):
    return self.weight*self.price

  @property#读值。
  def weight(self):
    return self.__weight#真正的值存储在私有属性中。

  @weight.setter
  def weight(self,value):
    if value >0:
      self.__weight=value#有效值存入私有属性中。
    else:
      raise ValueError('Value must be > 0')#对于无效的值抛出ValueError。

Tipps: Wenn wir eine schreibgeschützte Eigenschaft festlegen müssen, verwenden Sie nur @property, ohne @func.setter .

Prinzipanalyse: Um das Prinzip des @property-Dekorators besser zu verstehen, schreiben wir eine Version des Codes, die den gleichen Effekt hat, aber den Dekorator nicht verwendet.

class LineItem:
  def __init__(self, description, weight, price):
    self.description = description
    self.weight = weight
    self.price = price

  def subtotal(self):
    return self.weight * self.price

  def get_weight(self): #普通读值方法。
    return self.__weight

  def set_weight(self, value): #普通设值方法。
    if value > 0:
      self.__weight = value
    else:
      raise ValueError('value must be > 0')
  weight = property(get_weight, set_weight) #构建property对象,赋值给公开的类特性。

Vollständige Unterschrift des Grundstückserbauers:

property(fget=None, fset=None, fdel=None, doc=None)

3. Feature-Factory-Funktion

Es gibt zwei Möglichkeiten, Features abstrakt zu definieren: Eine besteht darin, die Feature-Factory-Funktion zu verwenden, und die andere darin, die Deskriptorklasse zu verwenden.
Im Folgenden verwenden wir die Feature-Factory-Funktion, um den oben genannten Fall der Auftragsabwicklung abzuschließen:

def quantity(storage_name): 

  def qty_getter(instance): # instance指的是要把属性存储其中的LineItem实例。
    return instance.__dict__[storage_name] # 引用闭包中的自由变量storage_name,值直接从instance.__dict__中获取,以便跳过特性,防止无限递归。

  def qty_setter(instance, value): 
    if value > 0:
      instance.__dict__[storage_name] = value # 同理存储,跳过特性。
    else:
      raise ValueError('value must be > 0')

  return property(qty_getter, qty_setter) # 构建自定义特性对象并返回。

class LineItem:
  weight = quantity('weight') # 将自定义特性weight定义为类属性。
  price = quantity('price') # 同上。

  def __init__(self, description, weight, price):
    self.description = description
    self.weight = weight # 此处特性已经激活,可验证值的有效性。
    self.price = price

  def subtotal(self):
    return self.weight * self.price # 此处利用特性获取实例中存储的值。

4. Verwenden Sie Features, um Attribute zu löschen

class BlackKnight:
 def __init__(self):
   self.members = ['an arm', 'another arm',
           'a leg', 'another leg']
   self.phrases = ["'Tis but a scratch.",
           "It's just a flesh wound.",
           "I'm invincible!",
           "All right, we'll call it a draw."]

 @property
 def member(self):
   print('next member is:')
   return self.members[0]

 @member.deleter
 def member(self):
   text = 'BLACK KNIGHT (loses {})\n-- {}'
   print(text.format(self.members.pop(0), self.phrases.pop(0)))

Um ein Attribut zu löschen, geben Sie einfach den Befehl im Hauptprogramm ein: del obj.attr

3. Wichtige Attribute und Funktionen zur Verarbeitung von Attributen

1 🎜>

    __class__: ein Verweis auf die Klasse, zu der das Objekt gehört (d. h. obj.__class__ hat die gleiche Wirkung wie type(obj)). Einige spezielle Methoden in Python, wie zum Beispiel __getattr__, werden nur in der Klasse des Objekts gesucht, nicht in der Instanz.
  • __dict__: Eine Karte, die beschreibbare Attribute eines Objekts oder einer Klasse speichert.
  • __slots__: Klassen können dieses Attribut definieren, um die Attribute einer Instanz einzuschränken.

2. Integrierte Funktion

    dir([object]): Listet die meisten Objekte auf .
  • getattr(object,name[,default]): Ruft das Attribut ab, das der Namenszeichenfolge aus dem Objektobjekt entspricht. Die erhaltenen Eigenschaften können aus der Klasse oder Oberklasse stammen, zu der das Objekt gehört.
  • hasattr(object,name): Wenn das angegebene Attribut im Objektobjekt vorhanden ist oder das angegebene Attribut auf irgendeine Weise (z. B. durch Vererbung) über das Objektobjekt erhalten werden kann, wird zurückgegeben WAHR.
  • setattr(object,name,value): Setzt den Wert des angegebenen Attributs des Objektobjekts auf Wert, vorausgesetzt, dass das Objektobjekt diesen Wert akzeptieren kann. Diese Funktion kann eine neue Eigenschaft erstellen oder eine vorhandene Eigenschaft überschreiben.
  • var([object]): Gibt das __dict__-Attribut des Objektobjekts zurück.

3. Spezielle Methoden

    __delattr__(self,name): Verwenden Sie einfach die del-Anweisung, um Attribute löschen, diese Methode wird aufgerufen.
  • __dir__(self): Wird aufgerufen, wenn das Objekt an die dir-Funktion übergeben wird und die Attribute auflistet.
  • __getattr__(self,name): Wird nur aufgerufen, wenn das Abrufen des angegebenen Attributs fehlschlägt und nach der Suche nach obj, Klasse und Superklasse.
  • __getattribute__(self,name): Diese Methode wird immer aufgerufen, wenn versucht wird, das angegebene Attribut abzurufen. Eine Ausnahme besteht jedoch, wenn es sich bei dem gesuchten Attribut um ein spezielles Attribut oder eine spezielle Methode handelt. Um eine unendliche Rekursion zu verhindern, sollte die Implementierung der Methode __getattribute__ super().__getattribute__(obj,name) verwenden.
  • __setattr__(self,name,value): Diese Methode wird immer aufgerufen, wenn versucht wird, das angegebene Attribut festzulegen. Die integrierten Funktionen dot und setattr
  • lösen diese Methode aus.
  • Verwandte Empfehlungen:

Detaillierte Erklärung der Verwendung der for-Schleife in Python_python

Detaillierte Erklärung von Python Erweiterte Funktionen mit Beispielen Verwendung von


Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der dynamischen Eigenschaften und Merkmale in Python_python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn