Python_python의 동적 속성 및 특성에 대한 자세한 설명

不言
풀어 주다: 2018-04-08 10:45:25
원래의
1458명이 탐색했습니다.

이 글은 Python의 동적 속성과 기능에 대한 자세한 설명을 주로 소개합니다. 편집자가 꽤 좋다고 생각해서 지금 공유하고 참고용으로 제공하겠습니다. 에디터와 함께 구경해보세요

소개: 이 글은 파이썬에서 메타프로그래밍의 기초를 배우면서 제가 얻은 핵심 지식과 개인적인 경험을 기록하고 있습니다. 파이썬을 시작하려는 친구들이 와서 함께 배우고 소통할 수 있습니다.

1. 동적 속성을 사용하여 JSON 데이터 소스 처리

속성: Python에서는 데이터 속성과 데이터 처리 방법을 총칭하여 속성이라고 합니다.

메타 프로그래밍: 프로그래밍에 메타클래스를 사용합니다. 메타클래스 → 클래스 → 객체 메타클래스는 클래스보다 더 추상적이며 클래스의 클래스를 생성합니다.

1. 동적 속성을 사용하여 JSON 클래스 데이터에 액세스

초판: json.load(fp)를 사용하여 데이터 검토

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原生对象。
로그인 후 복사

동적 속성을 사용하여 JSON 클래스 데이터에 액세스

Second edition 첫 번째 버전에서 deep data를 조회하는 형식은 Feed'Schedule'40과 같이 상대적으로 길다. 그리고 클래스의 두 번째 버전은 재귀적일 수 있으며 중첩된 맵과 목록을 자동으로 처리할 수 있습니다.

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
로그인 후 복사

분석: FronenJSON 클래스의 핵심은 __getattr__ 메서드입니다. 인터프리터는 일반적인 방법을 사용하여 속성을 얻을 수 없는 경우(즉, 지정된 속성을 인스턴스, 클래스 또는 슈퍼클래스에서 찾을 수 없는 경우)에만 특수 __getattr__ 메서드를 호출합니다.

2. 유효하지 않은 속성 이름 처리

Python에서는 키워드가 예약되어 있으므로 키워드로 명명된 속성은 유효하지 않습니다. 따라서 두 번째 버전에서는 __init__을 개선해야 합니다:

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

3. 특수 메서드 __new__

3번째 버전: __new__ 생성자를 사용하여 클래스를 유연한 객체 팩토리 함수로 변환합니다.

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. 특징

1. 클래스 속성, 인스턴스 속성, 프라이빗 속성 및 특징

클래스 속성: 클래스 속성은 __init__() 외부에서 초기화되고 클래스에 속합니다. 모든 인스턴스는 하나의 속성을 공유합니다.
호출 방법: 클래스 속성은 내부적으로는 classname.class 속성명을 사용하여 호출되고, 외부에서는 classname.class 속성명 또는 인스턴스 이름.class 속성명을 사용하여 호출할 수 있습니다.

인스턴스 속성: 인스턴스 속성은 각 인스턴스에 속하며 서로 간섭하지 않습니다.

개인 속성:

  1. 단일 밑줄로 시작 _: 이는 단지 이것이 개인 속성이며 외부 세계에서 계속 액세스하고 변경할 수 있음을 다른 사람에게 알립니다.

  2. 이중 밑줄로 시작 __: 외부적으로는 instancename.propertyname을 통해 액세스하거나 변경할 수 없습니다. 실제로는 _classname__propertyname으로 변환됩니다.

특성: 인스턴스 속성을 관리하는 데 사용되는 클래스 속성입니다.
기능 사용: 공용 속성을 읽기 값 메서드 및 값 설정 메서드를 사용하여 관리되는 속성으로 전환하고 클라이언트 코드에 영향을 주지 않고 비즈니스 규칙을 구현하는 데 자주 사용됩니다.

참고:

  1. 인스턴스 속성과 클래스 속성에 동일한 이름을 사용하지 마세요. 그렇지 않으면 인스턴스 속성이 클래스 속성을 덮어 찾기 어려운 오류가 발생합니다.

  2. 인스턴스 속성은 클래스 속성을 모호하게 만들지 않지만, 클래스 속성은 인스턴스 속성을 모호하게 만듭니다.

obj.attr은 obj 인스턴스에서 attr을 찾기 시작하지 않고 obj.__class__에서 찾기 시작하며 Python은 클래스에 attr이라는 속성이 없는 경우에만 인스턴스에서 attr을 찾기 때문입니다.

즉, 커버리지 수준으로 보면 클래스 속성 > 인스턴스 속성 > 클래스 속성이 됩니다.

2. 특성을 사용하여 속성 확인

특성을 사용하면 인스턴스 속성의 유효성을 확인할 수 있으며 동시에 알려진 속성과 속성 간의 관계를 기반으로 다른 속성을 조정하여 하드 코딩을 피할 수 있습니다.
사례: 매장에서 견과류, 곡물 등 다양한 유기농 식품을 판매한다고 가정해 보겠습니다. 각 고객의 주문에는 매장의 일련의 제품이 포함됩니다. 고객의 주문을 기준으로 총 가격을 계산해야 합니다.

분석: 우리는 고객 주문의 제품 중량이 양수가 아닌 숫자가 되는 것을 원하지 않습니다. 인스턴스 속성의 유효성을 확인하기 위해 값을 얻고 설정하려면 @property 데코레이터를 사용해야 합니다. 코드는 다음과 같습니다.

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。
로그인 후 복사

팁: 읽기 전용 속성을 설정해야 하는 경우 @func.setter를 사용하지 않고 @property만 사용하세요.

원리 분석: @property 데코레이터의 원리를 더 잘 이해하기 위해 동일한 효과를 가지지만 데코레이터를 사용하지 않는 버전의 코드를 작성합니다.

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对象,赋值给公开的类特性。
로그인 후 복사

property 생성자 메서드의 전체 서명:

property(fget=None, fset=None, fdel=None, doc=None)
로그인 후 복사

3 기능을 추상적으로 정의하는 방법에는 두 가지가 있습니다. 하나는 기능 팩토리 기능을 사용하는 것입니다. 다른 하나는 설명 Symbol 클래스를 사용하는 것입니다. 아래에서는 기능 팩토리 기능을 사용하여 위에서 언급한 주문 정산 사례를 완료합니다.


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. 기능을 사용하여 속성 삭제

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)))
로그인 후 복사

메인 프로그램 :del obj.attr

3. 속성 처리를 위한 중요한 속성 및 함수

1. 특수 속성

  • __class__: 객체가 속한 클래스에 대한 참조(예: obj.__class__ 및 type(obj) ) 같은 효과가 있습니다 ). __getattr__과 같은 Python의 일부 특수 메소드는 인스턴스가 아닌 객체의 클래스에서만 검색됩니다.

  • __dict__: 개체나 클래스의 쓰기 가능한 속성을 저장하는 맵입니다.

  • __slots__: 클래스는 이 속성을 정의하여 인스턴스가 갖는 속성을 제한할 수 있습니다.

2. 내장 함수

  • dir([object]): 객체의 대부분의 속성을 나열합니다.

  • getattr(object,name[,default]): 객체 객체에서 이름 문자열에 해당하는 속성을 가져옵니다. 획득된 속성은 객체가 속한 클래스나 슈퍼클래스에서 나올 수 있습니다.

  • hasattr(object,name): 지정된 속성이 객체 객체에 존재하거나 지정된 속성을 어떤 방식(예: 상속)으로 객체 객체를 통해 얻을 수 있는 경우 True를 반환합니다.

  • setattr(object,name,value): 객체 객체가 해당 값을 허용할 수 있는 경우 객체 객체의 지정된 속성 값을 value로 설정합니다. 이 함수는 새 속성을 생성하거나 기존 속성을 덮어쓸 수 있습니다.

  • var([object]): 객체 객체의 __dict__ 속성을 반환합니다.

3. 특수 메서드

  • __delattr__(self,name): 이 메서드는 속성을 삭제하기 위해 del 문을 사용할 때마다 호출됩니다.

  • __dir__(self): 객체가 dir 함수에 전달되고 속성을 나열할 때 호출됩니다.

  • __getattr__(self,name): 지정된 속성을 얻는 데 실패하고 obj, 클래스 및 슈퍼 클래스를 검색한 후에만 호출됩니다.

  • __getattribute__(self,name): 이 메서드는 지정된 속성을 가져오려고 할 때 항상 호출됩니다. 그러나 검색 중인 속성이 특수한 속성이나 메소드인 경우는 예외입니다. 무한 재귀를 방지하기 위해 __getattribute__ 메서드 구현에서는 super().__getattribute__(obj,name)을 사용해야 합니다.

  • __setattr__(self,name,value): 이 메서드는 지정된 속성을 설정하려고 할 때 항상 호출됩니다. 점 기호 및 setattr 내장 함수

  • 가 이 메서드를 트리거합니다.

관련 권장사항:

Python_python

Python 고급 함수 사용에 대한 자세한 설명 예


위 내용은 Python_python의 동적 속성 및 특성에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿