2015-01-09 4 views
3

저는 현재 파이썬에서 처음으로 더 큰 프로젝트를 작성하고 있으며 클래스의 하위 클래스 클래스 본문에서 실행할 수 있도록 클래스 메소드를 정의하는 방법에 대해 궁금합니다.Ruby가 파이썬에서 DSL을 사용합니다.

첫 번째로 더 많은 내용을 들려주고, (이 질문에 필수적이지 않은 모든 것을 제거했습니다.) 루비에서 내가하려고하는 일을 어떻게 수행하는지 예 : 클래스를 정의하면 Item처럼 이 : 지금까지 내가 파이썬에서 비슷한 일을 달성하려고 지금

class MyItem < Item 
    define_field("name") 
end 

item = MyItem.new 
item.name = "World" 
puts "Hello #{item.name}!" 

을,하지만 난 내가 지금까지있어 결과에 만족하지 않다 :

class Item 
    def initialize(data={}) 
    @data = data 
    end 

    def self.define_field(name) 
    define_method("#{name}"){ instance_variable_get("@data")[name.to_s] } 
    define_method("#{name}=") do |value| 
     instance_variable_get("@data")[name.to_s] = value 
    end 
    end 
end 

I는 다음과 같이 사용할 수 있습니다 :

class ItemField(object): 
    def __init__(self, name): 
     self.name = name 
    def __get__(self, item, owner=None): 
     return item.values[self.name] 
    def __set__(self, item, value): 
     item.values[self.name] = value 
    def __delete__(self, item): 
     del item.values[self.name] 

class Item(object): 
    def __init__(self, data=None): 
     if data == None: data = {} 
     self.values = data 
     for field in type(self).fields: 
      self.values[field.name] = None 
      setattr(self, field.name, field) 
    @classmethod 
    def define_field(cls, name): 
     if not hasattr(cls, "fields"): cls.fields = [] 
     cls.fields.append(ItemField(name, default)) 

이제 define_field을 하위 클래스의 본문에서 호출하는 방법을 알 수 없습니다. 이것은 내가 그것이 가능하다는 것을 바란 것입니다 :

class MyItem(Item): 
    define_field("name") 

item = MyItem({"name": "World"}) 
puts "Hello {}!".format(item.name) 
item.name = "reader" 
puts "Hello {}!".format(item.name) 

this similar question이야하지만 답변을 아무도 정말 만족없고, 누군가가 __func__()과 기능을 caling 권장하지만 난 할 수 없어 추측이 내가 할 수 없기 때문에 익명의 몸체에서 클래스에 대한 참조를 얻으십시오. (이 문제에 대해 제가 틀렸다면 수정하십시오.) 다른 사람은 이것을하기 위해 모듈 레벨 함수를 사용하는 것이 더 낫다고 지적했습니다. 이것은 또한 가장 쉬운 방법이라고 생각합니다 ,하지만이 일을하는 주된 의도는 하위 클래스의 구현을 깨끗하게 만들고 해당 모듈 함수를로드해야하는 것이 좋지 않을 수도 있다는 것입니다. (또한 클래스 클래스 밖에서 함수 호출을해야 할 것입니다.하지만 이건 지저분하다고 생각합니다.)

기본적으로 파이썬은 허용되지 않도록하기 때문에 내 접근 방식이 잘못되었다고 생각합니다. 이런 종류의 일을해야합니다. Ruby 예제에서와 같이 Python으로 뭔가를 달성하는 가장 좋은 방법은 무엇입니까?

(이미 단지 define_field 방법에 대한 매개 변수의 배열을 반환하는 서브 클래스의 메소드를하는 것에 대한 생각했습니다 더 좋은 방법이 없다면.)

답변

2

아마도 클래스 메소드를 호출하는 것이 올바른 경로가 아닙니다. 나는 정확히 의 속도를 내고 있지 않다. 파이썬이 클래스를 생성하는 방법과시기는 정확히이지만 클래스 메소드를 호출하여 속성을 생성 할 때 클래스 객체가 아직 존재하지 않는다고 생각한다.

레코드처럼 만들려는 것 같습니다. 첫째, 파이썬은 당신이 생성 한 후 사용자가 만든 클래스에 속성을 추가 할 수 있습니다 :

class Foo(object): 
    pass 

>>> foo = Foo() 
>>> foo.x = 42 
>>> foo.x 
42 

은 어쩌면 당신은 사용자가 설정할 수있는 특성 제한하고자합니다. 한 가지 방법이 있습니다.

class Item(object): 
    def __init__(self): 
     if type(self) is Item: 
      raise NotImplementedError("Item must be subclassed.") 

    def __setattr__(self, name, value): 
     if name not in self.fields: 
      raise AttributeError("Invalid attribute name.") 
     else: 
      self.__dict__[name] = value 

class MyItem(Item): 
    fields = ("foo", "bar", "baz") 

그래서 :

>>> m = MyItem() 
>>> m.foo = 42  # works 
>>> m.bar = "hello" # works 
>>> m.test = 12  # raises AttributeError 

마지막으로, 위의 예처럼, fields을 정의하지 않고 당신에게 사용자 서브 클래스 Item 수를 :

class MyItem(Item): 
    pass 

이 말하는 비밀 속성 오류가 발생합니다 속성 fields을 (를) 찾을 수 없습니다. 메타 클래스을 사용하여 클래스 생성시 fields 특성을 정의하도록 요구할 수 있습니다. 또한, 당신이 할 수있는 거리에 추상적 인 당신이 메타 클래스 사용하여 작성한 슈퍼 클래스에서 상속하여 메타 클래스를 지정하는 사용자의 필요 :

class ItemMetaclass(type): 
    def __new__(cls, clsname, bases, dct): 
     if "fields" not in dct: 
      raise TypeError("Subclass must define 'fields'.") 
     return type.__new__(cls, clsname, bases, dct) 

class Item(object): 
    __metaclass__ = ItemMetaclass 
    fields = None 

    def __init__(self): 
     if type(self) == Item: 
      raise NotImplementedError("Must subclass Type.") 

    def __setattr__(self, name, value): 
     if name in self.fields: 
      self.__dict__[name] = value 
     else: 
      raise AttributeError("The item has no such attribute.") 

class MyItem(Item): 
    fields = ("one", "two", "three") 
1

당신은 거의 다 왔어! 내가 제대로 이해하는 경우 :

class Item(object): 
    def __init__(self, data=None): 
     fields = data or {} 
     for field, value in data.items(): 
      if hasattr(self, field): 
       setattr(self, field, value) 
    @classmethod 
    def define_field(cls, name): 
     setattr(cls, name, None) 

편집 :은 내가 아는 한, 그것을 정의하는 동안 클래스가 정의되고 액세스 할 수 없습니다.

class Something(Item): 
    def __init__(self): 
     type(self).define_field("name") 

을하지만 당신은 바퀴를 개혁하고 있습니다 : 당신은 그러나 __init__ 방법에 메서드를 호출 할 수 있습니다.

+1

을 나는 아마 내 질문에 충분히 명확하지 않았다 미안 해요 ,하지만 내 진짜 문제는 하위 클래스에서'define_field' 메서드를 호출하는 방법을 잘 모르겠다는 것입니다. 방금 내 질문을 편집했습니다. – evotopid

+0

오, 나는 그것이 가능하다고 생각하지 않는다. 그래도'__init__' 안에서 할 수 있습니다. – Kroltan

1

클래스를 정의 할 때 자체 정의 블록 내에서 클래스 자체를 참조 할 수 없습니다. 따라서 define_field(...)MyItem으로 정의한 후에 전화해야합니다. 예 :

class MyItem(Item): 
    pass 
MyItem.define_field("name") 

item = MyItem({"name": "World"}) 
print("Hello {}!".format(item.name)) 
item.name = "reader" 
print("Hello {}!".format(item.name)) 
관련 문제